自定义步骤View--StepView

最近遇到一个按步骤走流程的需求,相信其他的程序员也会遇到这样的需求吧,好了下面说一下我解决这个问题的过程


刚接到这个需求的时候,我是使用布局的方式画的,很长很乱,适配是发现,那是相当的烂啊,根本无法满足适配的需要,无语啊。代码就不贴了哈。


还是转换思路,自己写吧,于是就简单的写一个。代码如下:

思路如下:

   先写出7个方法,每个方法实现的是每个步骤的状态,画出圆点、连线、每个步骤的名称


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;


public class StepView extends View {
    private int mWidth;//view的总宽度
    private Bitmap curImage;//当前步骤图片
    private Bitmap passedImage;//已完成步骤图片
    private Bitmap unPassImage;//未完成步骤图片
    private Paint paint;//bitmap使用的画笔

    private Paint linePaint;//画线使用的画笔
    private float lineWidth;//步骤之间每根线的长度
    private int lineCount = 6;//共多少条连线
    /**
     * 当前图片与未完成和完成图片大小不一致
     * 且图片要在一条直线上,因此,画完成和未完成
     * 的图片时要计算出marginTop
     */
    private float unpassTop = 0;

    private Paint textPait;//画文字时需要的画笔
    private int curIndex = 0;//当前步骤
    private int marginTop = 40;//文字与图片之间的间距

    public StepView(Context context) {
        super(context);
        init();
    }

    public StepView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public StepView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init(){
        //初始化图片
        curImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_current);
        passedImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_passed);
        unPassImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_unpass);

        //初始化画笔
        paint = new Paint();

        linePaint = new Paint();
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(5);
        linePaint.setColor(Color.parseColor("#cfcfcf"));

        textPait = new Paint();
        textPait.setAntiAlias(true);
        textPait.setTextSize(36);
        textPait.setColor(Color.parseColor("#eeaa2f"));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //设置宽度,随着view的宽度的变化而变化
        this.mWidth = w;
        //计算步骤之间线条的长度
        lineWidth = (float)(mWidth - passedImage.getWidth() * lineCount - curImage.getWidth()) / lineCount;
        //计算完成与未完成图片与View顶部的间距
        unpassTop = (curImage.getHeight() - unPassImage.getHeight()) / 2;
    }

    
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float startX = 0;
        for(int i = 0; i<= lineCount; i++){
            //先画点,当前步骤之前为已完成,当前步骤之后为未完成
            if(curIndex > i){
                drawCircleBitmap(canvas,startX,passedImage,unpassTop);
            }else if(curIndex == i){
                drawCircleBitmap(canvas,startX,curImage,0);
            }else{
                drawCircleBitmap(canvas,startX,unPassImage,unpassTop);
            }

            //画文字
            drawText(i,canvas,startX,curIndex);

            //画线条
            if(curIndex > i){
                //计算新的起始位置
                startX += passedImage.getWidth();
                drawLine(canvas,startX,Color.parseColor("#eeaa2f"));
            }else if(curIndex == i){
                if(i != 6){
                    //计算新的起始位置
                    startX += curImage.getWidth();
                    drawLine(canvas,startX,Color.parseColor("#cfcfcf"));
                }
            }else{
                if(i != 6){
                    //计算新的起始位置
                    startX += unPassImage.getWidth();
                    drawLine(canvas,startX,Color.parseColor("#cfcfcf"));
                }

            }
            //计算新的起始位置
            startX += lineWidth;
        }
    }

    private void drawCircleBitmap(Canvas canvas,float startX,Bitmap bitmap,float marginTop){
        canvas.drawBitmap(bitmap,startX,marginTop,paint);
    }

    private void drawLine(Canvas canvas,float startX,int color){
        linePaint.setColor(color);
        canvas.drawLine(startX,curImage.getHeight() / 2,startX + lineWidth,curImage.getHeight() / 2,linePaint);
    }

    private void drawText(int index,Canvas canvas,float startX,int curIndex){
        if(index <= curIndex){
            textPait.setColor(Color.parseColor("#eeaa2f"));
        }else{
            textPait.setColor(Color.parseColor("#cfcfcf"));
        }
        if(index == 0){
            canvas.drawText("第一步",0,curImage.getHeight() + marginTop,textPait);
        }else if(index == 1){
            if(curIndex == 1){
                canvas.drawText("第二步",startX - 25,curImage.getHeight() + marginTop,textPait);
            }else{
                canvas.drawText("第二步",startX - 35,curImage.getHeight() + marginTop,textPait);
            }
        }else if(index == 2){
            if(curIndex == 2){
                canvas.drawText("第三步",startX - 25,curImage.getHeight() + marginTop,textPait);
            }else{
                canvas.drawText("第三步",startX - 35,curImage.getHeight() + marginTop,textPait);
            }
        }else if(index == 3){
            if(curIndex == 3){
                canvas.drawText("第四步",startX - 25,curImage.getHeight() + marginTop,textPait);
            }else{
                canvas.drawText("第四步",startX - 35,curImage.getHeight() + marginTop,textPait);
            }
        }else if(index == 4){
            if(curIndex == 4){
                canvas.drawText("第五步",startX - 25,curImage.getHeight() + marginTop,textPait);
            }else{
                canvas.drawText("第五步",startX - 35,curImage.getHeight() + marginTop,textPait);
            }
        }else if(index == 5){
            if(curIndex == 5){
                canvas.drawText("第六步",startX - 25,curImage.getHeight() + marginTop,textPait);
            }else{
                canvas.drawText("第六步",startX - 35,curImage.getHeight() + marginTop,textPait);
            }
        }else if(index == 6){
            canvas.drawText("第七步",mWidth - 90,curImage.getHeight() + marginTop,textPait);
        }
    }

    public void setCurIndex(int curIndex) {
        this.curIndex = curIndex;
        invalidate();
    }
}
 
 
以上的代码是有缺陷,当文字大小改变后,产生的问题需要重新计算,这对适配来说是非常痛苦的,在使用过程中发现了这个问题,故对比做了进一步的优化。
public class StepView extends View {
    private int mWidth;//view的总宽度
    private Bitmap curImage;//当前步骤图片
    private Bitmap passedImage;//已完成步骤图片
    private Bitmap unPassImage;//未完成步骤图片
    private Paint paint;//bitmap使用的画笔

    private Paint linePaint;//画线使用的画笔
    private float lineWidth;//步骤之间每根线的长度
    private int lineCount = 0;//共多少条连线
    /**
     * 当前图片与未完成和完成图片大小不一致
     * 且图片要在一条直线上,因此,画完成和未完成
     * 的图片时要计算出marginTop
     */
    private float unpassTop = 0;

    private Paint textPait;//画文字时需要的画笔
    private int curIndex = 0;//当前步骤
    private int marginTop = 15;//文字与图片之间的间距
    private int textSize = 12;//文字大小
    private int passedImageWidth;
    private int curImageWidth;
    private int unpassImageWidth;
    private int startTextY;
    private String[] texts = {"第一步", "第二步", "第三步", "第四步", "第五步", "第六步", "第七步"};
    private float[] textLengths = new float[7];


    public StepView(Context context) {
        super(context);
        init(context);
    }

    public StepView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public StepView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        //初始化图片
        curImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_current);
        passedImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_passed);
        unPassImage = BitmapFactory.decodeResource(getResources(), R.drawable.process_unpass);
        textSize = dip2px(context, textSize);
        marginTop = dip2px(context, marginTop);
        lineCount = texts.length - 1;
        passedImageWidth = passedImage.getWidth();
        curImageWidth = curImage.getWidth();
        unpassImageWidth = unPassImage.getWidth();
        startTextY = curImage.getHeight() + marginTop;
        //初始化画笔
        paint = new Paint();

        linePaint = new Paint();
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(5);
        linePaint.setColor(Color.parseColor("#cfcfcf"));

        textPait = new Paint();
        textPait.setAntiAlias(true);
        textPait.setTextSize(textSize);
        textPait.setColor(Color.parseColor("#eeaa2f"));
        for (int i = 0, len = texts.length; i < len; i++) {
            textLengths[i] = getTextLength(texts[i]);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //设置宽度,随着view的宽度的变化而变化
        this.mWidth = w;
        //计算步骤之间线条的长度
        lineWidth = (float) (mWidth - passedImageWidth * lineCount - curImageWidth) / lineCount;
        //计算完成与未完成图片与View顶部的间距
        unpassTop = (curImage.getHeight() - unPassImage.getHeight()) / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float startX = 0;
        for (int i = 0; i <= lineCount; i++) {
            //先画点,当前步骤之前为已完成,当前步骤之后为未完成
            if (curIndex > i) {
                drawCircleBitmap(canvas, startX, passedImage, unpassTop);
            } else if (curIndex == i) {
                drawCircleBitmap(canvas, startX, curImage, 0);
            } else {
                drawCircleBitmap(canvas, startX, unPassImage, unpassTop);
            }

            //画文字
            drawText(i, canvas, startX, curIndex, curIndex == i);

            //画线条
            if (curIndex > i) {
                //计算新的起始位置
                startX += passedImageWidth;
                drawLine(canvas, startX, Color.parseColor("#eeaa2f"));
            } else if (curIndex == i) {
                if (i != 6) {
                    //计算新的起始位置
                    startX += curImageWidth;
                    drawLine(canvas, startX, Color.parseColor("#cfcfcf"));
                }
            } else {
                if (i != 6) {
                    //计算新的起始位置
                    startX += unpassImageWidth;
                    drawLine(canvas, startX, Color.parseColor("#cfcfcf"));
                }

            }
            //计算新的起始位置
            startX += lineWidth;
        }
    }

    private void drawCircleBitmap(Canvas canvas, float startX, Bitmap bitmap, float marginTop) {
        canvas.drawBitmap(bitmap, startX, marginTop, paint);
    }

    private void drawLine(Canvas canvas, float startX, int color) {
        linePaint.setColor(color);
        canvas.drawLine(startX, curImage.getHeight() / 2, startX + lineWidth, curImage.getHeight() / 2, linePaint);
    }

    private void drawText(int index, Canvas canvas, float startX, int curIndex, boolean isCur) {
        int div = isCur ? curImageWidth / 2 : passedImageWidth / 2;
        if (index <= curIndex) {
            textPait.setColor(Color.parseColor("#eeaa2f"));
        } else {
            textPait.setColor(Color.parseColor("#cfcfcf"));
        }
        if (index == 0) {
            canvas.drawText(texts[0], 0, startTextY, textPait);
        } else if (index == texts.length - 1) {
            canvas.drawText(texts[texts.length - 1], mWidth - textLengths[index], startTextY, textPait);
        } else {
            canvas.drawText(texts[index], startX + div - textLengths[index] / 2, startTextY, textPait);
        }
    }

    public void setCurIndex(int curIndex) {
        this.curIndex = curIndex;
        invalidate();
    }

    private float getTextLength(String text) {
        // 使用panit获取文字的宽度
        float textLength = textPait.measureText(text);
        return textLength;
    }

    /**
     * dip 2 px
     *
     * @param context
     * @param dipValue
     * @return 上午11:37:12
     */
    private int dip2px(Context context, int dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale);
    }

}
 
以上就是全部的代码实现,初步的封装了步骤的变化,其实还可以进一步封装,比如自定义属性,步骤总数、步骤标题集合,已完成步骤的颜色、当前步骤颜色、未完成步骤颜色等等,希望有兴趣的同学进行进一步的封装

需要的图片资源已经上传,本想着把第一步即每个步骤为一个方法实现的代码贴出来的,实在是太麻烦啦,就算啦。
 
欢迎各位指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值