Android中水平结点进度条StepHorizontalView

本文介绍了一种自定义的水平步骤视图控件的实现方法,包括布局、使用方式及属性讲解。该控件可用于展示多步骤流程,通过设置不同属性实现进度显示和样式定制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、先看看效果,是不是你需要的

二 、使用方式

        StepHorizontalView mStepSv = (StepHorizontalView) findViewById(R.id.sv_step);
        mStepSv.setProgress(3, 4);
        List<String> list = new ArrayList<>();
        list.add("第一步");
        list.add("第二步");
        list.add("第三步");
        list.add("第四步");
        mStepSv.setTitles(list);

三、布局

<com.example.zyt.mystepview.mine.StepHorizontalView
        android:id="@+id/sv_step"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:background="@android:color/darker_gray"
        app:h_bg_color="@color/colorPrimaryDark"
        app:h_bg_radius="6dp"
        app:h_bg_width="4dp"
        app:h_pro_color="@android:color/holo_red_light"
        app:h_pro_radius="6dp"
        app:h_pro_width="5dp"
        app:h_max_step="5"
        app:h_pro_step="2"
        app:h_text_padding="30dp"
        app:h_textsize="16sp" />

四、属性讲解

1. h_bg_color                 默认进度条的颜色

2. h_bg_radius               默认节点的半径大小

3. h_bg_width                 默认间隔线的宽度

4. h_pro_color                已过进度条的颜色

5. h_pro_radius              已过节点的半径大小

6. h_pro_width               已过间隔线的宽度

7. h_text_padding          进度条与文本的距离

8. h_textsize                  文本的字体大小

9. h_max_step               最多节点的个数

10. h_pro_step              节点的进度

五、自定义控件

public class StepHorizontalView extends View {

    private int bgWidth;
    private int bgHeight;
    private float bgRadius;
    private float proRadius;
    private float startX;
    private float stopX;
    private float bgCenterY;
    private int lineBgWidth;
    private int bgColor;
    private int lineProWidth;
    private int proColor;
    private int textPadding;
    private int maxStep;
    private int textSize;
    private int proStep;
    private Paint bgPaint;
    private Paint proPaint;
    private int interval;
    private List<String> titles;
    private Map<String, Integer> map;
    private float startLine;
    private float stopLine;

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

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

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

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FlowViewHorizontal);
        bgRadius = ta.getDimension(R.styleable.FlowViewHorizontal_h_bg_radius, 10);
        proRadius = ta.getDimension(R.styleable.FlowViewHorizontal_h_pro_radius, 8);
        lineBgWidth = (int) ta.getDimension(R.styleable.FlowViewHorizontal_h_bg_width, 3f);
        bgColor = ta.getColor(R.styleable.FlowViewHorizontal_h_bg_color, Color.parseColor("#cccccc"));
        lineProWidth = (int) ta.getDimension(R.styleable.FlowViewHorizontal_h_pro_width, 2f);
        proColor = ta.getColor(R.styleable.FlowViewHorizontal_h_pro_color, Color.parseColor("#EF5350"));
        textPadding = (int) ta.getDimension(R.styleable.FlowViewHorizontal_h_text_padding, 20);
        maxStep = ta.getInt(R.styleable.FlowViewHorizontal_h_max_step, 6);
        textSize = (int) ta.getDimension(R.styleable.FlowViewHorizontal_h_textsize, 20);
        proStep = ta.getInt(R.styleable.FlowViewHorizontal_h_pro_step, 1);
        ta.recycle();
        initView();
    }

    private void initView() {
        bgPaint = new Paint();
        bgPaint.setAntiAlias(true);   // 锯齿
        bgPaint.setStyle(Paint.Style.FILL);
        bgPaint.setColor(bgColor);
        bgPaint.setStrokeWidth(lineBgWidth);
        bgPaint.setTextSize(textSize);
        bgPaint.setTextAlign(Paint.Align.CENTER);

        proPaint = new Paint();
        proPaint.setAntiAlias(true);
        proPaint.setStyle(Paint.Style.FILL);
        proPaint.setColor(proColor);
        proPaint.setStrokeWidth(lineProWidth);
        proPaint.setTextSize(textSize);
        proPaint.setTextAlign(Paint.Align.CENTER);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode == MeasureSpec.EXACTLY) {
            bgWidth = widthSize;
        } 

        if (heightMode == MeasureSpec.EXACTLY) {
            bgHeight = heightSize;
        }

        interval = (int) ((bgWidth-bgRadius*2-getPaddingRight()-getPaddingLeft())/(maxStep - 1));//紧挨着的两个圆心的距离
        startLine = getPaddingLeft() + bgRadius * 2;//作为线的起点
        stopLine = getPaddingLeft() + interval * (maxStep-1);//作为线的终点
        startX = getPaddingLeft() + bgRadius;//作为圆的起始点
        stopX = stopLine + bgRadius;//作为最后一个圆的圆心   bgWidth - bgRadius - getPaddingRight()
        bgCenterY = getPaddingTop()+bgRadius;//作为线和圆心的纵坐标
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawBg(canvas);
        drawProgress(canvas);
        drawText(canvas);
    }

    /**
     * 绘画文本
     * @param canvas
     */
    private void drawText(Canvas canvas) {
        for (int i = 0; i < maxStep; i++) {
            if (i < proStep) {
                if (null != titles && i < titles.size()) {
                    canvas.drawText(titles.get(i), startX + (i * interval), bgCenterY + textPadding + (bgRadius < proRadius ? proRadius : bgRadius), proPaint);
                }
            } else {
                if (null != titles && i < titles.size()) {
                    String title = titles.get(i);
                    if (null == title) {
                        continue;
                    }
                    canvas.drawText(title, startX + (i * interval), bgCenterY + textPadding + (bgRadius < proRadius ? proRadius : bgRadius), bgPaint);
                }
            }
        }
    }

    /**
     * 绘画底部默认进度条
     * @param canvas
     */
    private void drawBg(Canvas canvas) {
        canvas.drawLine(startLine, bgCenterY, stopLine, bgCenterY, bgPaint);
        for (int i = 0; i < maxStep; i++) {
            canvas.drawCircle(startX + (i * interval), bgCenterY, bgRadius, bgPaint);
        }
    }

    /**
     * 绘画进度
     * @param canvas
     */
    private void drawProgress(Canvas canvas) {
        for (int i = 0; i < proStep; i++) {
            canvas.drawCircle(startX + (i * interval), bgCenterY, proRadius, proPaint);

            canvas.drawLine(startX, bgCenterY, startX + (i * interval), bgCenterY, proPaint);
        }
    }

    /**
     * 进度设置
     *
     * @param progress 已完成到哪部
     * @param maxStep  总步骤
     */
    public void setProgress(int progress, int maxStep) {
        proStep = progress;
        this.maxStep = maxStep;
        invalidate();
    }

    public void setTitles(List<String> titles){
        this.titles = titles;
    }
}

六、在values中创建一个attrs.xml文件

    <!--step view -->
    <declare-styleable name="FlowViewHorizontal">
        <attr name="h_bg_radius" format="dimension" />
        <attr name="h_pro_radius" format="dimension" />
        <attr name="h_bg_width" format="dimension" />
        <attr name="h_pro_width" format="dimension" />
        <attr name="h_bg_color" format="color" />
        <attr name="h_pro_color" format="color" />
        <attr name="h_text_padding" format="dimension" />
        <attr name="h_max_step" format="integer" />
        <attr name="h_textsize" format="dimension" />
        <attr name="h_pro_step" format="integer" />
    </declare-styleable>

七、不足之处

这个控件不能wrap_content,但不会报错,只是效果和match_parent一样,所以尽量写明具体高度。

若有问题,请大家多多指正。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值