Swipe the progress cursor left and right
The source file was written by other big guys. I made some deletions on the basis of the original one; it is mainly used as a record; the following is the complete code after modification;
# public class DoubleSlideSeekBar extends View {<!-- --> /** * The width of the line (progress bar) */ private int lineWidth; /** * The length of the line (progress bar) */ private int lineLength = 400; /** * The height of the word is 100$ */ private float textHeight; private int textToImg = 20;//The distance between the font and the top image /** * cursor image width */ private int imageWidth; /** * cursor image height */ private int imageHeight; /** * Whether the cursor on the left is moving */ private boolean isLowerMoving; /** * Whether the cursor on the right is moving */ private boolean isUpperMoving; /** * word size 100$ */ private int textSize; /** * word color 100$ */ private int textColor; /** * The color of the line (progress bar) inside the two cursors */ private int inColor = Color. BLUE; /** * The color of the outer line (progress bar) of the two cursors */ private int outColor = Color. BLUE; /** * The color of the scale */ private int ruleColor = Color. BLUE; /** * The color of the words above the scale */ private int ruleTextColor = Color. BLUE; /** * Picture of the icon on the left */ private Bitmap bitmapLow; /** * Picture of the icon on the right */ private Bitmap bitmapBig; /** * The position of the left icon on the X-axis */ private int slideLowX; /** * The position of the X-axis where the icon on the right is located */ private int slideBigX; /** * Icon (cursor) height */ private int bitmapHeight; /** * Icon (cursor) width */ private int bitmapWidth; /** * Add some padding size as appropriate so that our custom view can be displayed completely */ private int paddingLeft = 25; private int paddingRight = 25; private int paddingTop = 20; private int paddingBottom = 20; /** * The position where the line (progress bar) starts */ private int lineStart = paddingLeft; /** * The Y axis position of the line */ private int lineY; /** * The end position of the line (progress bar) */ private int lineEnd = lineLength + paddingLeft; /** * The maximum value of the selector */ private int bigValue = 360; /** * The minimum value of the selector */ private int smallValue = 0; /** * The current minimum value of the selector */ private float smallRange = 0; /** * The current maximum value of the selector */ private float bigRange = 360; /** * unit: yuan */ private String unit = ""; /** * The height of the tick marks */ private Paint linePaint; private Paint bitmapPaint; private Paint textPaint; public DoubleSlideSeekBar(Context context) {<!-- --> this(context, null); } public DoubleSlideSeekBar(Context context, @Nullable AttributeSet attrs) {<!-- --> this(context, attrs, 0); } public DoubleSlideSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {<!-- --> super(context, attrs, defStyleAttr); TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DoubleSlideSeekBar, defStyleAttr, 0); int size = typedArray. getIndexCount(); for (int i = 0; i < size; i ++ ) {<!-- --> int type = typedArray. getIndex(i); if (type == R.styleable.DoubleSlideSeekBar_inColor) {<!-- --> inColor = typedArray. getColor(type, Color. BLACK); } else if (type == R.styleable.DoubleSlideSeekBar_lineHeight) {<!-- --> lineWidth = (int) typedArray. getDimension(type, dip2px(getContext(), 10f)); } else if (type == R.styleable.DoubleSlideSeekBar_outColor) {<!-- --> outColor = typedArray. getColor(type, Color. YELLOW); } else if (type == R.styleable.DoubleSlideSeekBar_textColor) {<!-- --> textColor = typedArray. getColor(type, Color. BLUE); } else if (type == R.styleable.DoubleSlideSeekBar_textSize) {<!-- --> textSize = typedArray.getDimensionPixelSize(type, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); } else if (type == R.styleable.DoubleSlideSeekBar_imageLow) {<!-- --> bitmapLow = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(type, 0)); } else if (type == R.styleable.DoubleSlideSeekBar_imageBig) {<!-- --> bitmapBig = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(type, 0)); } else if (type == R.styleable.DoubleSlideSeekBar_imageheight) {<!-- --> imageHeight = (int) typedArray. getDimension(type, dip2px(getContext(), 20f)); } else if (type == R.styleable.DoubleSlideSeekBar_imagewidth) {<!-- --> imageWidth = (int) typedArray. getDimension(type, dip2px(getContext(), 20f)); } else if (type == R.styleable.DoubleSlideSeekBar_ruleColor) {<!-- --> ruleColor = typedArray. getColor(type, Color. BLUE); } else if (type == R.styleable.DoubleSlideSeekBar_ruleTextColor) {<!-- --> ruleTextColor = typedArray. getColor(type, Color. BLUE); } else if (type == R.styleable.DoubleSlideSeekBar_unit) {<!-- --> unit = typedArray. getString(type); } else if (type == R.styleable.DoubleSlideSeekBar_bigValue) {<!-- --> bigValue = typedArray. getInteger(type, 100); } else if (type == R.styleable.DoubleSlideSeekBar_smallValue) {<!-- --> smallValue = typedArray. getInteger(type, 100); } } typedArray. recycle(); init(); } private void init() {<!-- --> /** The default image of the cursor */ if (bitmapLow == null) {<!-- --> bitmapLow = BitmapFactory.decodeResource(getResources(), R.drawable.icon_bar_seek); } if (bitmapBig == null) {<!-- --> bitmapBig = BitmapFactory.decodeResource(getResources(), R.drawable.icon_bar_seek); } /**The real height of the cursor image, and then the image can be set to the desired size by scaling*/ bitmapHeight = bitmapLow. getHeight(); bitmapWidth = bitmapLow. getWidth(); // set desired size int newWidth = imageWidth; int newHeight = imageHeight; // calculate scaling float scaleWidth = ((float) newWidth) / bitmapWidth; float scaleHeight = ((float) newHeight) / bitmapHeight; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); /** zoom image */ bitmapLow = Bitmap.createBitmap(bitmapLow, 0, 0, bitmapWidth, bitmapHeight, matrix, true); bitmapBig = Bitmap.createBitmap(bitmapBig, 0, 0, bitmapWidth, bitmapHeight, matrix, true); /** Reacquire the width and height of the cursor image */ bitmapHeight = bitmapLow. getHeight(); bitmapWidth = bitmapLow. getWidth(); /*Get the padding of the component*/ paddingLeft = getPaddingLeft(); paddingRight = getPaddingRight(); paddingTop = getPaddingTop(); paddingBottom = getPaddingBottom(); /*Initialize text paint*/ if (textPaint == null) {<!-- --> textPaint = new Paint(); } textPaint.setColor(textColor); textPaint.setTextSize(textSize); textPaint.setAntiAlias(true); textPaint.setTextAlign(Paint.Align.CENTER); Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); textHeight = fontMetrics.bottom - fontMetrics.top; //Initialize the brush of the line linePaint = new Paint(); linePaint.setAntiAlias(true); linePaint.setStrokeWidth(lineWidth); linePaint.setColor(inColor); linePaint.setStrokeCap(Paint.Cap.ROUND); //Initialize size value smallRange = smallValue; bigRange = bigValue; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {<!-- --> int width = getMyMeasureWidth(widthMeasureSpec); int height = getMyMeasureHeight(heightMeasureSpec); setMeasuredDimension(width, height); } private int getMyMeasureHeight(int heightMeasureSpec) {<!-- --> int mode = MeasureSpec. getMode(heightMeasureSpec); int size = MeasureSpec. getSize(heightMeasureSpec); if (mode == MeasureSpec. EXACTLY) {<!-- --> size = (int) Math.max(size, paddingBottom + paddingTop + bitmapHeight + textHeight / 2 + 5 + textToImg); } else {<!-- --> //wrap content int height = (int) (paddingBottom + paddingTop + bitmapHeight + textHeight / 2 + 5 + textToImg); size = Math.min(size, height); } return size; } private int getMyMeasureWidth(int widthMeasureSpec) {<!-- --> int mode = MeasureSpec. getMode(widthMeasureSpec); int size = MeasureSpec. getSize(widthMeasureSpec); if (mode == MeasureSpec. EXACTLY) {<!-- --> size = Math.max(size, paddingLeft + paddingRight + lineWidth + bitmapWidth); } else {<!-- --> //wrap content int width = paddingLeft + paddingRight + lineWidth + bitmapWidth; size = Math.min(size, width); } // match parent or fixed size At this point, the length of the line (progress bar) can be obtained lineLength = size - paddingLeft - paddingRight - bitmapWidth; //The end position of the line (progress bar) lineEnd = lineLength + paddingLeft + bitmapWidth / 2; //The starting position of the line (progress bar) lineStart = paddingLeft + bitmapWidth / 2; //Initialize cursor position slideBigX = lineEnd; slideLowX = lineStart; return size; } @Override protected void onDraw(Canvas canvas) {<!-- --> super.onDraw(canvas); // Y axis coordinates lineY = paddingTop + bitmapHeight / 2; // draw line linePaint.setColor(inColor); canvas.drawLine(slideLowX, lineY, slideBigX, lineY, linePaint); linePaint.setColor(outColor); // draw the outer line canvas. drawLine(lineStart, lineY, slideLowX, lineY, linePaint); canvas.drawLine(slideBigX, lineY, lineEnd, lineY, linePaint); // draw cursor if (bitmapPaint == null) {<!-- --> bitmapPaint = new Paint(); } canvas.drawBitmap(bitmapLow, slideLowX - bitmapWidth / 2, lineY - bitmapHeight / 2, bitmapPaint); canvas.drawBitmap(bitmapBig, slideBigX - bitmapWidth / 2, lineY - bitmapHeight / 2, bitmapPaint); //Draw the word above the cursor String minRange = String. format("%.0f" + unit, smallRange); String maxRange = String. format("%.0f" + unit, bigRange); canvas.drawText(minRange, slideLowX, lineY + bitmapHeight / 2 + textToImg + textHeight / 2, textPaint); canvas.drawText(maxRange, slideBigX, lineY + bitmapHeight / 2 + textToImg + textHeight / 2, textPaint); } @Override public boolean onTouchEvent(MotionEvent event) {<!-- --> //event mechanism super.onTouchEvent(event); float nowX = event. getX(); float nowY = event. getY(); switch (event. getAction()) {<!-- --> case MotionEvent. ACTION_DOWN: // Press on the line (progress bar) range boolean rightY = Math.abs(nowY - lineY) < bitmapHeight / 2; //press on the left cursor boolean lowSlide = Math.abs(nowX - slideLowX) < bitmapWidth / 2; //press on the right cursor boolean bigSlide = Math.abs(nowX - slideBigX) < bitmapWidth / 2; if (rightY & amp; & amp; lowSlide) {<!-- --> isLowerMoving = true; } else if (rightY & amp; & amp; bigSlide) {<!-- --> isUpperMoving = true; //Clicked on the line outside the cursor } else if (nowX >= lineStart & amp; & amp; nowX <= slideLowX - bitmapWidth / 2 & amp; & amp; rightY) {<!-- --> slideLowX = (int) nowX; updateRange(); postInvalidate(); } else if (nowX <= lineEnd & amp; & amp; nowX >= slideBigX + bitmapWidth / 2 & amp; & amp; rightY) {<!-- --> slideBigX = (int) nowX; updateRange(); postInvalidate(); } break; case MotionEvent. ACTION_MOVE: //The cursor on the left is in motion if (isLowerMoving) {<!-- --> //The current X coordinate is on the line and to the left of the right cursor if (nowX <= slideBigX & amp; & amp; nowX >= lineStart - bitmapWidth / 2) {<!-- -->//Can overlap // if (nowX <= slideBigX - bitmapWidth & amp; & amp; nowX >= lineStart - bitmapWidth / 2) {//Cannot overlap slideLowX = (int) nowX; if (slideLowX < lineStart) {<!-- --> slideLowX = lineStart; } //update progress updateRange(); postInvalidate(); } } else if (isUpperMoving) {<!-- --> //The current X coordinate is on the line and to the right of the left cursor // if (nowX >= slideLowX + bitmapWidth & amp; & amp; nowX <= lineEnd + bitmapWidth / 2) {//Cannot overlap if (nowX >= slideLowX & amp; & amp; nowX <= lineEnd + bitmapWidth / 2) {<!-- --> //can overlap slideBigX = (int) nowX; if (slideBigX > lineEnd) {<!-- --> slideBigX = lineEnd; } //update progress updateRange(); postInvalidate(); } } break; //finger up case MotionEvent. ACTION_UP: isUpperMoving = false; isLowerMoving = false; break; default: break; } return true; } private void updateRange() {<!-- --> //Current left cursor value smallRange = computRange(slideLowX); //Current right cursor value bigRange = computRange(slideBigX); //Interface implements value transfer if (onRangeListener != null) {<!-- --> onRangeListener.onRange(smallRange, bigRange); } } /** * get the current value */ private float computRange(float range) {<!-- --> return (range - lineStart) * (bigValue - smallValue) / lineLength + smallValue; } public int dip2px(Context context, float dpValue) {<!-- --> final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * Get the current Slide value */ private float computSlide(float range) {<!-- --> return (range - smallValue) * lineLength / (bigValue - smallValue) + lineStart; } /** * reset value */ public void resetRange(float low, float big) {<!-- --> this. smallRange = low; this.bigRange = big; slideLowX = (int) computSlide(low); slideBigX = (int) computSlide(big); postInvalidate(); } /** * Write an interface to pass the maximum and minimum values */ public interface onRangeListener {<!-- --> void onRange(float low, float big); } private onRangeListener onRangeListener; public void setOnRangeListener(DoubleSlideSeekBar.onRangeListener onRangeListener) {<!-- --> this.onRangeListener = onRangeListener; } }
resource
<!--line (progress bar) width--> <attr name="lineHeight" format="dimension" /> <!--The size of the word is 100 yuan--> <attr name="textSize" format="dimension" /> <!--The color of the word 100 yuan--> <attr name="textColor" format="color" /> <!--The color of the line (progress bar) inside the two cursors--> <attr name="inColor" format="color" /> <!--The color of the outer line (progress bar) of the two cursors--> <attr name="outColor" format="color" /> <!--Picture of the icon on the left--> <attr name="imageLow" format="reference"/> <!--Picture of the icon on the right--> <attr name="imageBig" format="reference"/> <!--cursor image width--> <attr name="imagewidth" format="dimension" /> <!--cursor image height--> <attr name="imageheight" format="dimension" /> <!--Is there a tick mark--> <attr name="hasRule" format="boolean" /> <!--The color of the scale--> <attr name="ruleColor" format="color" /> <!--The color of the words above the scale--> <attr name="ruleTextColor" format="color" /> <!--unit Yuan--> <attr name="unit" format="string"/> <!--Number of copies--> <attr name="equal" format="integer"/> <!--Scale unit $--> <attr name="ruleUnit" format="string"/> <!--The size of the text above the scale--> <attr name="ruleTextSize" format="dimension" /> <!--The height of the tick mark--> <attr name="ruleLineHeight" format="dimension" /> <!--The maximum value of the selector--> <attr name="bigValue" format="integer"/> <!--The minimum value of the selector--> <attr name="smallValue" format="integer"/> <declare-styleable name="DoubleSlideSeekBar"> <attr name="lineHeight" /> <attr name="textSize" /> <attr name="textColor" /> <attr name="inColor" /> <attr name="outColor" /> <attr name="imageLow"/> <attr name="imageBig"/> <attr name="imagewidth" /> <attr name="imageheight" /> <attr name="hasRule" /> <attr name="ruleColor" /> <attr name="ruleTextColor" /> <attr name="unit" /> <attr name="equal" /> <attr name="ruleUnit" /> <attr name="ruleTextSize" /> <attr name="ruleLineHeight" /> <attr name="bigValue" /> <attr name="smallValue" /> </declare-styleable>
xml layout:
<com.cn.app.widget.DoubleSlideSeekBar android:id="@ + id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="5dp" app:imageheight="22dp" app:imagewidth="20dp" app:inColor="#9B91CD" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@ + id/tv" app:lineHeight="2dp" app:outColor="#E3E2ED" app:textColor="#9B91CD" app:textSize="14sp" />
This is the first time I use it, mainly for recording, please forgive me if I offend you!