Android 自定义圆形渐变色拖动条取色工具

Android 自定义圆形渐变色拖动条取色工具

效果图

效果图

public class CirqueColorPickerView extends View {
    
    
    /**
     * 画笔对象的引用
     */
    private Paint paint;

    /**
     * 中心点坐标
     */
    private int centerX, centerY;
    /**
     * 渐变色圆环半径
     */
    private int radius;

    private int paddingOuterThumb;

    /**
     * 圆环的颜色
     */
    private int roundColor;
    /**
     * 渐变色圆环宽度
     */
    private float roundWidth;
    /**
     * 外圈圆环颜色
     */
    private int outRoundColor;

    /**
     * 内圈小圆环颜色
     */
    private int inRoundColor;
    /**
     * 连线画笔
     */
    private Paint linePaint;
    /**
     * 连线颜色
     */
    private int lineColor;
    /**
     * 连线宽度
     */
    private float lineWidth;

    /**
     * 最大进度
     */
    private int max;

    /**
     * 当前进度
     */
    private int progress;

    /**
     * 中间进度百分比的字符串的颜色
     */
    private int textColor;

    /**
     * 中间进度百分比的字符串的字体
     */
    private float textSize;

    /**
     * 当前选中的颜色
     */
    private int currentColor = Color.RED;

    private Drawable mDragDrawable, mDragPressDrawable;

    public CirqueColorPickerView(Context context) {
    
    
        this(context, null);
    }

    public CirqueColorPickerView(Context context, AttributeSet attrs) {
    
    
        this(context, attrs, 0);
    }

    public CirqueColorPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
    
    
        super(context, attrs, defStyleAttr);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CirqueColorPickerView);

        paint = new Paint();
        linePaint = new Paint();

        //获取自定义属性和默认值
        roundColor = typedArray.getColor(R.styleable.CirqueColorPickerView_round_color,Color.RED);
        roundWidth = typedArray.getInteger(R.styleable.CirqueColorPickerView_round_width,40);

        outRoundColor = typedArray.getColor(R.styleable.CirqueColorPickerView_out_round_color,Color.WHITE);
        inRoundColor = Color.BLACK;
        textColor = typedArray.getColor(R.styleable.CirqueColorPickerView_text_color,Color.WHITE);
        textSize = typedArray.getInteger(R.styleable.CirqueColorPickerView_text_size,100);

        max = typedArray.getInteger(R.styleable.CirqueColorPickerView_max,360);
        lineColor = typedArray.getColor(R.styleable.CirqueColorPickerView_line_color,Color.WHITE);
        lineWidth = typedArray.getInteger(R.styleable.CirqueColorPickerView_line_width,10);

        // 加载拖动图标
        mDragDrawable = getResources().getDrawable(R.drawable.ring_dot);// 圆点图片
        int thumbHalfheight = mDragDrawable.getIntrinsicHeight() / 2;
        int thumbHalfWidth = mDragDrawable.getIntrinsicWidth() / 2;
        mDragDrawable.setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth, thumbHalfheight);

        mDragPressDrawable = getResources().getDrawable(R.drawable.ring_dot);// 圆点图片
        thumbHalfheight = mDragPressDrawable.getIntrinsicHeight() / 2;
        thumbHalfWidth = mDragPressDrawable.getIntrinsicWidth() / 2;
        mDragPressDrawable.setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth, thumbHalfheight);
        paddingOuterThumb = thumbHalfheight;
    }


    @Override
    public void onDraw(Canvas canvas) {
    
    
        /**
         * 画渐变色大圆环
         */
        SweepGradient sweepGradient = new SweepGradient(centerX, centerY,
                new int[]{
    
    
                        Color.rgb(107, 18, 248),
                        Color.rgb(254, 0, 198),
                        Color.rgb(255, 6, 19),
                        Color.rgb(255, 172, 40),
                        Color.rgb(146, 255, 54),
                        Color.rgb(1, 255, 53),
                        Color.rgb(0, 245, 234),
                        Color.rgb(1, 69, 249),
                        Color.rgb(107, 18, 248),
                },
                null);
        paint.setShader(sweepGradient);//设置圆环的渐变色
        paint.setStyle(Paint.Style.STROKE); //设置空心
        paint.setStrokeWidth(roundWidth); //设置圆环的宽度
        paint.setAntiAlias(true);  //消除锯齿
        canvas.drawCircle(centerX, centerY, radius, paint); //画出渐变色圆环
        /**
         * 画渐变色大圆环的边
         */
        linePaint.setColor(outRoundColor);//设置最外圈圆环的颜色
        linePaint.setStyle(Paint.Style.STROKE); //设置空心
        linePaint.setStrokeWidth(lineWidth); //设置圆环的宽度
        linePaint.setAntiAlias(true);  //消除锯齿
        canvas.drawCircle(centerX, centerY,  (int) (radius + roundWidth / 2 ), linePaint);

        /**
         * 画中间圆
         */
        linePaint.setStyle(Paint.Style.FILL);
        linePaint.setColor(getCurrentColor());
        canvas.drawCircle(centerX, centerY, (float) (radius/2.2), linePaint);

        /**
         * 画中间圆的边
         */
        linePaint.setColor(outRoundColor);//设置最外圈圆环的颜色
        linePaint.setStyle(Paint.Style.STROKE); //设置空心
        linePaint.setStrokeWidth(lineWidth); //设置圆环的宽度
        linePaint.setAntiAlias(true);  //消除锯齿
        canvas.drawCircle(centerX, centerY,(float) (radius/2.2)+lineWidth/2, linePaint);
        /**
         * 画内部小圆的边
         */
        RadialGradient radialGradient = new RadialGradient(
                centerX,centerY,(float) (radius/5)+lineWidth*4,
                new int[]{
    
    
                        0x99000000,
                        0x00ffffff,
//                        Color.rgb(0, 0, 0),
//                        Color.rgb(255, 255, 255),
                },null, Shader.TileMode.CLAMP
                );
        linePaint.setShader(radialGradient);
//        linePaint.setColor(inRoundColor);//设置最外圈圆环的颜色
        linePaint.setStyle(Paint.Style.STROKE); //设置空心
        linePaint.setStrokeWidth(lineWidth*4); //设置圆环的宽度
        linePaint.setAntiAlias(true);  //消除锯齿
        canvas.drawCircle(centerX, centerY,(float) (radius/5)+lineWidth*2, linePaint);
        linePaint.setShader(null);

        /**
         * 画文字
         */
        linePaint.setStrokeWidth(0);
        linePaint.setColor(textColor);
        linePaint.setTextSize(textSize);
        linePaint.setStyle(Paint.Style.FILL);
        String text = String.valueOf(progress);
        float textWidth = linePaint.measureText(text);   //测量字体宽度,我们需要根据字体的宽度设置在圆环中间
        canvas.drawText(text, centerX - textWidth / 2, centerY + textSize / 2, linePaint);

        linePaint.setTextSize(38);
        Path path = new Path();
        RectF oval = new RectF(centerX - (float) (radius/3.5), centerY - (float) (radius/3.5), centerX + (float) (radius/3.5), centerY + (float) (radius/3.5));  //用于定义的圆弧的形状和大小的界限
        path.addArc(oval,220,320);
        canvas.drawTextOnPath("ADD COLOUR",path,0, 0, linePaint);

        /**
         * 外圈大圆环上的点
         */
        PointF progressPoint = ChartUtils.calcArcEndPointXY(centerX, centerY, radius, 360 * progress / max, 90);
        /**
         * 画外圈大圆环上的点的边
         */
        linePaint.setColor(outRoundColor);//设置最外圈圆环的颜色
        linePaint.setStyle(Paint.Style.STROKE); //设置空心
        linePaint.setStrokeWidth(lineWidth); //设置圆环的宽度
        linePaint.setAntiAlias(true);  //消除锯齿
        canvas.drawCircle(progressPoint.x, progressPoint.y,(float) (roundWidth*1.5)+lineWidth/2, linePaint);

        /**
         * 内圈小圆环上的点
         */
        PointF proPoint = ChartUtils.calcArcEndPointXY(centerX, centerY, (float) (radius/5), 360 * progress / max, 90);
        /**
         * 两点之间的连接线
         */
        linePaint.setColor(lineColor);  //设置连线的颜色
        linePaint.setStrokeWidth(lineWidth);//设置连线的宽度
        canvas.drawLine(proPoint.x,proPoint.y,progressPoint.x,progressPoint.y,linePaint);
        /**
         * 大圆环上的点
         */
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(progressPoint.x, progressPoint.y, (float) (roundWidth*1.5), paint);
        canvas.save();
    }
    private boolean downOnArc = false;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
    
    
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action) {
    
    
            case MotionEvent.ACTION_DOWN:
                if (isTouchArc(x, y)) {
    
    
                    downOnArc = true;
                    updateArc(x, y);
                    return true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (downOnArc) {
    
    
                    updateArc(x, y);
                    changColor();
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                downOnArc = false;
                invalidate();
                if (changeListener != null) {
    
    
                    changeListener.onProgressChangeEnd(max, progress);
                }
                break;
        }
        return super.onTouchEvent(event);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
    
    
    //解决父视图滑动冲突
        switch (ev.getAction()) {
    
    
            case MotionEvent.ACTION_DOWN:
                getParent().getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_UP:
                getParent().getParent().requestDisallowInterceptTouchEvent(false);
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
    @Override
    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
    
    
        centerX = width / 2;
        centerY = height / 2;
        int minCenter = Math.min(centerX, centerY);
        //圆环的半径
        radius = (int) (minCenter - roundWidth / 2 - paddingOuterThumb);
        minValidateTouchArcRadius = (int) (radius - paddingOuterThumb * 1.5f);
        maxValidateTouchArcRadius = (int) (radius + paddingOuterThumb * 1.5f);
        super.onSizeChanged(width, height, oldw, oldh);
    }
    // 根据点的位置,更新进度
    private void updateArc(int x, int y) {
    
    
        int cx = x - getWidth() / 2;
        int cy = y - getHeight() / 2;
        // 计算角度,得出(-1->1)之间的数据,等同于(-180°->180°)
        double angle = Math.atan2(cy, cx) / Math.PI;
        // 将角度转换成(0->2)之间的值,然后加上90°的偏移量
        angle = ((2 + angle) % 2 + (270 / 180f)) % 2;
        // 用(0->2)之间的角度值乘以总进度,等于当前进度
        progress = (int) (angle * max / 2);
        if (changeListener != null) {
    
    
            changeListener.onProgressChange(max, progress);
        }
        invalidate();
    }
    private int minValidateTouchArcRadius; // 最小有效点击半径
    private int maxValidateTouchArcRadius; // 最大有效点击半径
    // 判断是否按在圆边上
    private boolean isTouchArc(int x, int y) {
    
    
        double d = getTouchRadius(x, y);
        if (d >= minValidateTouchArcRadius && d <= maxValidateTouchArcRadius) {
    
    
            return true;
        }
        return false;
    }
    // 计算某点到圆点的距离
    private double getTouchRadius(int x, int y) {
    
    
        int cx = x - getWidth() / 2;
        int cy = y - getHeight() / 2;
        return Math.hypot(cx, cy);
    }
    public synchronized int getMax() {
    
    
        return max;
    }
    /**
     * 设置进度的最大值
     *
     * @param max
     */
    public synchronized void setMax(int max) {
    
    
        if (max < 0) {
    
    
            throw new IllegalArgumentException("max not less than 0");
        }
        this.max = max;
    }
    /**
     * 获取进度.需要同步
     *
     * @return
     */
    public synchronized int getProgress() {
    
    
        return progress;
    }
    /**
     * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
     * 刷新界面调用postInvalidate()能在非UI线程刷新
     *
     * @param progress
     */
    public synchronized void setProgress(int progress) {
    
    
        if (progress < 0) {
    
    
            throw new IllegalArgumentException("progress not less than 0");
        }
        if (progress > max) {
    
    
            progress = max;
        }
        if (progress <= max) {
    
    
            this.progress = progress;
            postInvalidate();
        }
    }
    private void changColor() {
    
    
        float colorH = (progress+1);
        currentColor = Color.HSVToColor(new float[]{
    
    colorH, 1.0f, 1.0f});
    }
    /**
     * 获取当前颜色
     *
     * @return
     */
    private int getCurrentColor() {
    
    
        return currentColor;
    }
    /**
     * 设置当前颜色
     *
     * @param currentColor
     */
    public void setCurrentColor(int currentColor) {
    
    
        this.currentColor = currentColor;
        if (onColorChangeListener != null) {
    
    
            onColorChangeListener.onColorChange(currentColor);
        }
        invalidate();
    }
    public int getCricleColor() {
    
    
        return roundColor;
    }
    public void setCricleColor(int cricleColor) {
    
    
        this.roundColor = cricleColor;
    }
    public float getRoundWidth() {
    
    
        return roundWidth;
    }
    public void setRoundWidth(float roundWidth) {
    
    
        this.roundWidth = roundWidth;
    }
    private OnProgressChangeListener changeListener;
    public void setChangeListener(OnProgressChangeListener changeListener) {
    
    
        this.changeListener = changeListener;
    }
    public interface OnProgressChangeListener {
    
    
        void onProgressChange(int duration, int progress);
        void onProgressChangeEnd(int duration, int progress);
    }
    private OnColorChangeListener onColorChangeListener;
    public void setOnColorChangerListener(OnColorChangeListener onColorChangerListener) {
    
    
        this.onColorChangeListener = onColorChangerListener;
    }
    public interface OnColorChangeListener {
    
    
        void onColorChange(int color);
    }
}

参考Android自定义控件-可拖动控制的圆环控制条
原文链接:https://blog.csdn.net/oQinYou/article/details/79131468

猜你喜欢

转载自blog.csdn.net/qq_45371893/article/details/126419874