Android View自定义多档位开关控件

效果:

分段式的进度条,支持单点、滑动更改进度,每一小段为一个整体,实际应用可以当做各种多档位调节开关使用。感觉该控件比较实用,便记录一下。

源码参考,修改了自己想要的样式,原博客样式圆角的https://blog.csdn.net/rexuezhonghun/article/details/126160548?spm=1001.2014.3001.5506

代码如下:

public class DragStepBar extends View {

    //背景颜色
    private int bgColor = Color.argb(255, 80, 80, 80);

    //渐变颜色
    private int gradientStart = Color.WHITE;
    private int gradientEnd = Color.WHITE;

    //遮罩颜色
    private int dividerColor = Color.BLACK;

    //画笔
    private Paint paint;

    //高度
    private int barHeight;

    //宽度
    private int barWidth;

    //步阶(开关的总档位数)
    private int step = 6;

    //当前步阶
    private int curStep = 0;

    //一段的宽度
    private float stepWidth;

    //分割线的宽度
    private float dividerWidth;

    //是否可以滑动
    private boolean touchEnable = true;
    private OnDragStepListener onDragStepListener;

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

    public DragStepBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragStepBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        DisplayMetrics displayMetrics = getDisplayMetrics();
        barWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 322, displayMetrics);
        barHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 28, displayMetrics);
        dividerWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, displayMetrics);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DragStepBar);

        //获取进度条背景色
        bgColor = a.getColor(R.styleable.DragStepBar_bar_bg, bgColor);
        //获取渐变色开始颜色
        gradientStart = a.getColor(R.styleable.DragStepBar_bar_color_start, gradientStart);
        //获取渐变色结束颜色
        gradientEnd = a.getColor(R.styleable.DragStepBar_bar_color_end, gradientEnd);
        //分割线颜色
        dividerColor = a.getColor(R.styleable.DragStepBar_bar_divider_color, dividerColor);
        //分割线宽度
        dividerWidth = a.getDimension(R.styleable.DragStepBar_bar_divider_width, dividerWidth);
        //总步数
        step = a.getInt(R.styleable.DragStepBar_bar_step_count, step);
        //当前步数
        curStep = a.getInt(R.styleable.DragStepBar_bar_cur_step, curStep);

        if (curStep > step)
            curStep = step;
        a.recycle();
        paint = new Paint();
    }

    private DisplayMetrics getDisplayMetrics() {
        return getResources().getDisplayMetrics();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制底部背景
        drawBackGround(canvas);
        //绘制步阶进度
        drawGradient(canvas);
        //绘制分割线
        drawShade(canvas);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {//宽高都是wrap_content,使用默认值
            setBarMeasure(barWidth, barHeight);
        } else if (widthMode == MeasureSpec.AT_MOST) {
            setBarMeasure(barWidth, heightSize);
        } else if (heightMode == MeasureSpec.AT_MOST) {
            setBarMeasure(widthSize, barHeight);
        } else {
            setBarMeasure(widthSize, heightSize);
        }
    }

    /**
     * 根据测量的宽高计算出单个进度的宽度和圆角的大小
     */
    private void setBarMeasure(int width, int height) {
        barWidth = width;
        barHeight = height;
        stepWidth = (barWidth - (step - 1) * dividerWidth) / step;
        setMeasuredDimension(width, height);
    }

    //绘制底色
    private void drawBackGround(Canvas canvas) {
        paint.reset();
        paint.setAntiAlias(true);//抗锯齿
        paint.setDither(true);//图形抖动
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(5);
        paint.setColor(bgColor);
        RectF rectF = new RectF(0, 0, barWidth, barHeight);
        canvas.drawRect(rectF, paint);
    }

    //绘制渐变色
    private void drawGradient(Canvas canvas) {
        if (curStep == 0) return;

        LinearGradient linearGradient = new LinearGradient(0, 0, barWidth, barHeight,
                gradientStart, gradientEnd, Shader.TileMode.MIRROR);

        // 设置画笔属性
        paint.setAntiAlias(true); // 抗锯齿
        paint.setDither(true); // 图形抖动
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(1);
        paint.setShader(linearGradient);

        // 绘制已完成进度的矩形
        float completedWidth = curStep * stepWidth + (curStep - 1) * dividerWidth;
        RectF completedRectF = new RectF(0, 0, completedWidth, barHeight);
        canvas.drawRect(completedRectF, paint);

        // 绘制未完成进度的矩形(可选,如果你想要显示未完成的部分)
        float remainingWidth = barWidth - completedWidth;
        if (remainingWidth > 0) {
            RectF remainingRectF = new RectF(completedWidth, 0, barWidth, barHeight);
            paint.setShader(null); // 移除渐变效果,可以使用纯色或其他效果
            canvas.drawRect(remainingRectF, paint);
        }
    }

    //绘制分割线
    private void drawShade(Canvas canvas) {
        paint.reset();
        paint.setColor(dividerColor);
        paint.setAntiAlias(true);//抗锯齿
        paint.setDither(true);//图形抖动
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(1);
        for (int i = 1; i < step; i++) {
            float left = stepWidth * i + dividerWidth * (i - 1);
            RectF rectF = new RectF(left, 0, left + dividerWidth, barHeight);
            canvas.drawRect(rectF, paint);
        }
    }

    //设置是否可点击
    public void setTouchEnable(boolean touchEnable) {
        this.touchEnable = touchEnable;
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!touchEnable) {
            return false;
        }
        //获取触摸坐标
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                updateStep(event.getX());
                if (onDragStepListener != null)
                    onDragStepListener.onDragStep(curStep, false);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                updateStep(event.getX());
                if (onDragStepListener != null)
                    onDragStepListener.onDragStep(curStep, true);
                break;
        }
        getParent().requestDisallowInterceptTouchEvent(true);
        return true;

    }

    private void updateStep(float x) {
        for (int i = 0; i < step; i++) {
            float startX = i * stepWidth + i * dividerWidth;
            float endX = (i == step - 1) ? barWidth : ((i + 1) * stepWidth + (i + 1) * dividerWidth);

            if (x > startX && x <= endX) {
                curStep = i + 1;
                invalidate();
                break;
            }
        }

    }

    //获取当前步阶
    public int getCurStep() {
        return curStep;
    }

    public void setOnDragStepListener(OnDragStepListener onDragStepListener) {
        this.onDragStepListener = onDragStepListener;
    }

    ///设置默认步阶
    public void setDefaultStep(int step) {
        curStep = step;
        invalidate();
    }

    public interface OnDragStepListener {
        void onDragStep(int step, boolean moveCancel);
    }
}
在项目style.xml添加基本属性:
  <declare-styleable name="DragStepBar">
        <!--渐变色开始色-->
        <attr name="bar_color_start" format="color"/>
        <!--渐变色结束色-->
        <attr name="bar_color_end" format="color"/>
        <!--进度条背景色-->
        <attr name="bar_bg" format="color"/>
        <!--分割线颜色-->
        <attr name="bar_divider_color" format="color"/>
        <!--分割线宽度-->
        <attr name="bar_divider_width" format="dimension"/>
        <!--总步数-->
        <attr name="bar_step_count" format="integer"/>
        <!--当前所在步数-->
        <attr name="bar_cur_step" format="integer"/>
    </declare-styleable>

布局中使用:

    <com.study.android.diyviewdemo.DragStepBar
        android:layout_width="wrap_content"
        android:layout_height="28dp"
        android:layout_marginTop="20dp"
        android:layout_marginStart="10dp"
        app:bar_step_count="5"
        app:bar_cur_step="3"
        app:bar_divider_width="1dp"
        android:paddingStart="16dp" />

完成

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值