android left and right sliding progress

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!