自定义view-流程进度条

现在大多牵扯到押金之类的app都会涉及到身份认证及开通业务或者退押金等业务,而这些操作属于一系列的流程操作,也需要一定的时间来完成所有如下图,所以想写一个关于认证流程类的自定义view来呈现这个业务。

在这里插入图片描述

一、分析View

我们先来定义状态概念和分析view的绘制流程

  1. 定义状态:
    1)未认证状态:❌
    2)认证完成状态:✅+ 外圈圆
    3)正在认证办理状态 : 原点和外圈圆
  2. 显示逻辑
    1)若任何一个流程都没有完成,我们则默认正在进行第一步认证流程,其他的流程为未认证;
    2)若其中一个流程已经完成,则当前流程之前的流程全部为认证完成,当前流程的下一个流程为正在认证状态,再剩下的就为未完成状态;
  3. 绘制流程
    1)首先分为两个部分,一个是文字部分,另一个是图片进度部分;
    2)我们先绘制图片进度部分,先对其进行拆分,可以分为中间基线(白色),然后完成和最近未完成之间粗基线,再者是对应的图片绘制;
    3)接下来再计算对应文字的位置来绘制对应文字部分
二、编码View
  1. 创建类CertificationProgress继承View

    public class CertificationProgress extends View {
        
        public CertificationProgress(Context context) {
            super(context);
        }
    
        public CertificationProgress(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CertificationProgress(Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    }
    
  2. 接下来应该是我们的测量工作,由于我们的view的测量和我们将使用到的三张图片的大小有关系,所以我们先创建init(Context context, AttributeSet attrs, int defStyleAttr)方法,并在其中加载获取我们需要的三个图片资源,这样我们就可以获取到图片的尺寸,作为我们对应的测量mode的数据参考;

    /**
         * 流程完成提示图
         */
        private Bitmap certification_finish_img;
        /**
         * 流程进行中提示图
         */
        private Bitmap certification_ing_img;
        /**
         * 流程未完成提示图
         */
        private Bitmap certification_not_finish_img;
    
        public CertificationProgress(Context context) {
            super(context);
            init(context, null, 0);
        }
    
        public CertificationProgress(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init(context, attrs, 0);
        }
    
        public CertificationProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs, defStyleAttr);
        }
    
        public void init(Context context, AttributeSet attrs, int defStyleAttr) {
            certification_finish_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_finish);
            certification_ing_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_ing);
            certification_not_finish_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_not_finish);
        }
    
  3. 测量部分,重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法,对于MeasureSpec.EXACTLY模式我们就直接使用系统测量出来的大小,剩下的两种模式MeasureSpec.AT_MOST、MeasureSpec.UNSPECIFIED,我们需要自己来规定我们view的宽高,对于View宽偷个懒就直接让其于屏幕宽度一致,我们着重来计算取舍一下view的高度,由效果图我们分析可以知道,在垂直方向主要的高度是paddingTop+paddingBottom+文字高度+三个图片中最高的值,为了更美观简洁大方点,我们需要给文字和对应图片进度条一定的间距,在文字的上下间距我们分别取文字高度的一半,为此根据内容来测量得到的高度就为:textHeight * 2 + (maxImgYRadio << 1) + getPaddingTop() + getPaddingBottom();我们将其和系统给我们的测量值比较取最小值。

    public class CertificationProgress extends View {
    
        /**
         * 流程完成提示图
         */
        private Bitmap certification_finish_img;
        /**
         * 流程进行中提示图
         */
        private Bitmap certification_ing_img;
        /**
         * 流程未完成提示图
         */
        private Bitmap certification_not_finish_img;
    
        /**
         * maxImgYRadio : 图片中Y轴方向最大半径
         * maxImgXRadio : 图片中X轴方向最大半径
         */
        private int maxImgYRadio, maxImgXRadio;
    
        /**
         * 文字高度
         */
        private int textHeight;
    
        /**
         * 文字画笔
         */
        private TextPaint mTextPaint;
        /**
         * 文字大小
         */
        private int textSize;
    
        /**
         * 流程步骤
         */
        private final String[] stepTextContent = {"手机验证", "实名认证", "开通业务", "注册完成"};
        /**
         * 流程步骤文字长度
         */
        private final float[] stepTextLength = new float[stepTextContent.length];
    
        
    
        public CertificationProgress(Context context) {
            super(context);
            init(context, null, 0);
        }
    
        public CertificationProgress(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init(context, attrs, 0);
        }
    
        public CertificationProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs, defStyleAttr);
        }
    
        public void init(Context context, AttributeSet attrs, int defStyleAttr) {
            certification_finish_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_finish);
            certification_ing_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_ing);
            certification_not_finish_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_not_finish);
            maxImgYRadio = Math.max(certification_ing_img.getHeight(), Math.max(certification_finish_img.getHeight(), certification_not_finish_img.getHeight())) >> 1;
            maxImgXRadio = Math.max(certification_ing_img.getWidth(), Math.max(certification_not_finish_img.getWidth(), certification_finish_img.getWidth())) >> 1;
    
            mTextPaint = new TextPaint();
            mTextPaint.setTextSize(textSize);
            
            //计算文字高度和对应文本的长度
            Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
            textHeight = (int) (fontMetrics.bottom - fontMetrics.top);
            for (int i = 0; i < stepTextContent.length; i++) {
                stepTextLength[i] = mTextPaint.measureText(stepTextContent[i]);
            }
        }
    
       
        
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int setWidth, setHeight;
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
            DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
            if (widthMode == MeasureSpec.EXACTLY) {
                setWidth = measureWidth;
            } else {
                setWidth = displayMetrics.widthPixels;
            }
    
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
            if (heightMode == MeasureSpec.EXACTLY) {
                setHeight = measureHeight;
            } else {
                int h = textHeight * 2 + (maxImgYRadio << 1) + getPaddingTop() + getPaddingBottom();
                setHeight = Math.min(h, measureHeight);
            }
            setMeasuredDimension(setWidth, setHeight);    }
    }
    
  4. 在测量完成后就是我们的绘制流程了,由于我们包含了padding值和受到图片中心位置的绘制影响,我们计算出实际绘制的区域宽高w、h,并将画布移动到对应绘制区域,减少我们在绘制时padding的计算工作量:

    	@Override
        protected void onDraw(Canvas canvas) {
            int w = getWidth() - getPaddingLeft() - getPaddingRight() - maxImgXRadio * 2;
            int h = getHeight() - getPaddingTop() - getPaddingBottom();
            canvas.translate(getPaddingLeft() + maxImgXRadio, getPaddingTop());
        }
    
  5. 根据上面已经分析过的绘制流程,我们可以先绘制文字或者先绘制图形,这里就先绘制图形吧,由于每一个步骤都有对应不同图形呈现,所以我们先定义变量step其取之范围为[0-4]和我们baseLineColor(这里不再讲述),第一步绘制baseLine,其分为2种情况,由于所有情形可以覆盖到对应最细线条上,所以不管任何情况我们先绘制最细的基准线条,接下来在绘制各个其他情况:
    1)所有流程均未完成,那么只有最基础的细线条,所以不做任何事情;
    2)将第一个流程点到当前完成到达点的下一个步骤点之间的线条加粗,剩下的其他线条全部不变,不做任何操作;最后将画笔重置,防止当前状态发生改变刷新:

    	@Override
        protected void onDraw(Canvas canvas) {
            int w = getWidth() - getPaddingLeft() - getPaddingRight() - maxImgXRadio * 2;
            int h = getHeight() - getPaddingTop() - getPaddingBottom();
            canvas.translate(getPaddingLeft() + maxImgXRadio, getPaddingTop());
            drawBaseLine(w, h, canvas);
        }
    	private void drawBaseLine(int w, int h, Canvas canvas) {
            mPaint.reset();
            mPaint.setColor(baseLineColor);
            canvas.drawLine(0, completeTop(h, null), w, completeTop(h, null), mPaint);
            mPaint.setStrokeWidth(10);
            if (step < 1) return;
            if (step < 2) {
                canvas.drawLine(0, completeTop(h, null), w / 3.0f, completeTop(h, null), mPaint);
            } else if (step < 3) {
                canvas.drawLine(0, completeTop(h, null), w * 2 / 3.0f, completeTop(h, null), mPaint);
            } else {
                canvas.drawLine(0, completeTop(h, null), w, completeTop(h, null), mPaint);
            }
            mPaint.reset();
        }
        
    
  6. 接下来就根据变量值step来绘制显示对应流程的图片,需要注意是,为了均匀绘制,我们需要在对应绘制中心点位置和图片X轴上的做半径来确定图形位置:

    	@Override
        protected void onDraw(Canvas canvas) {
            int w = getWidth() - getPaddingLeft() - getPaddingRight() - maxImgXRadio * 2;
            int h = getHeight() - getPaddingTop() - getPaddingBottom();
            canvas.translate(getPaddingLeft() + maxImgXRadio, getPaddingTop());
            drawBaseLine(w, h, canvas);
    
            drawStepOne(w, h, canvas);
            drawStepTwo(w, h, canvas);
            drawStepThree(w, h, canvas);
            drawStepFour(w, h, canvas);
        }
    	private void drawBaseLine(int w, int h, Canvas canvas) {
            mPaint.reset();
            mPaint.setColor(baseLineColor);
            canvas.drawLine(0, completeTop(h, null), w, completeTop(h, null), mPaint);
            mPaint.setStrokeWidth(10);
            if (step < 1) return;
            if (step < 2) {
                canvas.drawLine(0, completeTop(h, null), w / 3.0f, completeTop(h, null), mPaint);
            } else if (step < 3) {
                canvas.drawLine(0, completeTop(h, null), w * 2 / 3.0f, completeTop(h, null), mPaint);
            } else {
                canvas.drawLine(0, completeTop(h, null), w, completeTop(h, null), mPaint);
            }
            mPaint.reset();
        }
    
    
        /**
         * 0 为没有一个步骤通过,且正在进行第一个步骤
         * 1 第一个步骤完成,正在进行第二个步骤
         * 2 第二个步骤完成,正在进行第三个步骤
         * 3 第三个步骤完成,正在进行第四个步骤
         * 4 所有步骤完成
         */
        private void drawStepOne(int w, int h, Canvas canvas) {
            if (step < 1) {
                canvas.drawBitmap(certification_ing_img, -maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
            } else {
                canvas.drawBitmap(certification_ing_img, -maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
                canvas.drawBitmap(certification_finish_img, -certification_finish_img.getWidth() / 2.0f, completeTop(h, certification_finish_img), mPaint);
            }
    
        }
    
        private void drawStepTwo(int w, int h, Canvas canvas) {
            if (step < 1) {
                canvas.drawBitmap(certification_not_finish_img, w / 3.0f - certification_not_finish_img.getWidth() / 2.0f, completeTop(h, certification_not_finish_img), mPaint);
            } else if (step < 2) {
                canvas.drawBitmap(certification_ing_img, w / 3.0f - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
            } else {
                canvas.drawBitmap(certification_ing_img, w / 3.0f - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
                canvas.drawBitmap(certification_finish_img, w / 3.0f - certification_finish_img.getWidth() / 2.0f, completeTop(h, certification_finish_img), mPaint);
            }
    
        }
    
        private void drawStepThree(int w, int h, Canvas canvas) {
            if (step < 2) {
                canvas.drawBitmap(certification_not_finish_img, w * 2 / 3.0f - certification_not_finish_img.getWidth() / 2.0f, completeTop(h, certification_not_finish_img), mPaint);
            } else if (step < 3) {
                canvas.drawBitmap(certification_ing_img, w * 2 / 3.0f - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
            } else {
                canvas.drawBitmap(certification_ing_img, w * 2 / 3.0f - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
                canvas.drawBitmap(certification_finish_img, w * 2 / 3.0f - certification_finish_img.getWidth() / 2.0f, completeTop(h, certification_finish_img), mPaint);
            }
    
        }
    
        private void drawStepFour(int w, int h, Canvas canvas) {
            if (step < 3) {
                canvas.drawBitmap(certification_not_finish_img, w - certification_not_finish_img.getWidth() / 2.0f, completeTop(h, certification_not_finish_img), mPaint);
            } else if (step < 4) {
                canvas.drawBitmap(certification_ing_img, w - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
            } else {
                canvas.drawBitmap(certification_ing_img, w - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
                canvas.drawBitmap(certification_finish_img, w - certification_finish_img.getWidth() / 2.0f, completeTop(h, certification_finish_img), mPaint);
            }
    
        }
    
        private float completeTop(int h, Bitmap bitmap) {
            return (h + textHeight * 2 - (bitmap == null ? 0 : bitmap.getHeight())) / 2.0f;
        }
    
    

    来看一下初步效果:
    在这里插入图片描述
    还是不错的,由于基本效果是出来,由于我们step默认值是0,所以看不出完成部分进度的效果,后面我们将在测试环节来进行测试展示。

  7. 现在我们来绘制文字,主要还是计算出对应的文字绘制的位置x、y,其中x为对应位置分割中心点减去文字长度的一半,y等于textHeight*3/2-fontMetrics.bottom(由于文字距离图片有间隙,所以计算文字baseline时要取3/2):

    @Override
    protected void onDraw(Canvas canvas) {
        int w = getWidth() - getPaddingLeft() - getPaddingRight() - maxImgXRadio * 2;
        int h = getHeight() - getPaddingTop() - getPaddingBottom();
        canvas.translate(getPaddingLeft() + maxImgXRadio, getPaddingTop());
        drawBaseLine(w, h, canvas);
    
        drawStepOne(w, h, canvas);
        drawStepTwo(w, h, canvas);
        drawStepThree(w, h, canvas);
        drawStepFour(w, h, canvas);
        drawStepText(w, h, canvas);
    }
    
    
    
    private void drawStepText(int w, int h, Canvas canvas) {
        Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
        mTextPaint.setColor(textColor);
        for (int i = 0; i < stepTextContent.length; i++) {
            canvas.drawText(stepTextContent[i], i * w / 3.0f - stepTextLength[0] / 2.0f, textHeight * 3 / 2.0f - fontMetrics.bottom, mTextPaint);
        }
    }
    

    来看一下效果:
    在这里插入图片描述

  8. 到此基本效果已经完成来,最后是添加对于step的动态设置,如下(完整代码在最后给出):

     public void setStep(int step) {
            this.step = step;
            postInvalidate();
        }
    
三、测试View

编写四个按钮分别对应的step 0 - 4

  1. 布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.act.ViewActivity">
    
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/img_bg"
            android:orientation="horizontal">
    
            <vip.zhuahilong.mydefineview.widget.CertificationProgress
                android:id="@+id/certificationProgress"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:textSize="10dp"
                app:textColor="@color/white"
                android:layout_gravity="bottom"
                android:padding="10dp" />
    
        </LinearLayout>
    
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:orientation="horizontal"
            android:weightSum="5">
    
            <Button
                android:id="@+id/step0"
                android:layout_width="wrap_content"
                android:layout_height="?actionBarSize"
                android:layout_weight="1"
                android:text="step0"
                android:textAllCaps="false" />
    
            <Button
                android:id="@+id/step1"
                android:layout_width="wrap_content"
                android:layout_height="?actionBarSize"
                android:layout_weight="1"
                android:text="step1"
                android:textAllCaps="false" />
    
            <Button
                android:id="@+id/step2"
                android:layout_width="wrap_content"
                android:layout_height="?actionBarSize"
                android:layout_weight="1"
                android:text="step2"
                android:textAllCaps="false" />
    
            <Button
                android:id="@+id/step3"
                android:layout_width="wrap_content"
                android:layout_height="?actionBarSize"
                android:layout_weight="1"
                android:text="step3"
                android:textAllCaps="false" />
    
            <Button
                android:id="@+id/step4"
                android:layout_width="wrap_content"
                android:layout_height="?actionBarSize"
                android:layout_weight="1"
                android:text="step4"
                android:textAllCaps="false" />
    
    
        </LinearLayout>
    
        <vip.zhuahilong.mydefineview.widget.ALiPayWaitResultView
            android:id="@+id/viewAnimator"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:visibility="gone" />
    
    
    </RelativeLayout>
    
    
  2. activity代码

    public class ViewActivity extends BaseActivity {
    
        @BindView(R.id.certificationProgress)
        CertificationProgress mCertificationProgress;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_view);
    
        }
    
    
        @OnClick({R.id.step0, R.id.step1, R.id.step2, R.id.step3, R.id.step4})
        public void viewClick(View view) {
            switch (view.getId()) {
                case R.id.step0:
                    mCertificationProgress.setStep(0);
                    break;
                case R.id.step1:
                    mCertificationProgress.setStep(1);
                    break;
                case R.id.step2:
                    mCertificationProgress.setStep(2);
                    break;
                case R.id.step3:
                    mCertificationProgress.setStep(3);
                    break;
                case R.id.step4:
                    mCertificationProgress.setStep(4);
                    break;
            }
        }
    }
    
  3. 运行效果为:
    在这里插入图片描述
    点击step1,效果为:
    在这里插入图片描述
    点击step2,效果为:
    在这里插入图片描述
    点击step3,效果为:
    在这里插入图片描述
    点击step4,效果为:
    在这里插入图片描述
    点击step0,效果为:
    在这里插入图片描述

测试完美,这样我们自定义view-流程进度条就完成了,下次我们将对其进行改造,升级为动态设置步骤数量和步骤名称。点我瞬间移动到“自定义view-流程进度条动态调控”篇

四、代码
  1. 自定义属性文件

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="CertificationProgress">
            <attr name="textSize" format="dimension" />
            <attr name="textColor" format="color" />
            <attr name="baseLineColor" format="color" />
        </declare-styleable>
    </resources>
    
  2. 代码

    /**
     * @author :朱海龙
     * @date :Created in 2019-06-21 15:19
     * @description:关于认证进度等
     * @modified By:
     * @version:
     */
    public class CertificationProgress extends View {
    
        /**
         * 字体默认大小
         */
        public static final int defaultTextSize = 30;
        /**
         * 字体默认颜色
         */
        public static final int defaultTextColor = Color.BLACK;
        /**
         * 基线默认颜色
         */
        public static final int defaultBaseLineColor = Color.WHITE;
    
        /**
         * 文字画笔
         */
        private TextPaint mTextPaint;
        /**
         * 文字大小
         */
        private int textSize;
        /**
         * 文字颜色
         */
        private int textColor;
    
        /**
         * 文字高度
         */
        private int textHeight;
    
        /**
         * 基线颜色
         */
        private int baseLineColor;
    
        /**
         * 通用画笔
         */
        private Paint mPaint;
    
        /**
         * 流程完成提示图
         */
        private Bitmap certification_finish_img;
        /**
         * 流程进行中提示图
         */
        private Bitmap certification_ing_img;
        /**
         * 流程未完成提示图
         */
        private Bitmap certification_not_finish_img;
    
        /**
         * maxImgYRadio : 图片中Y轴方向最大半径
         * maxImgXRadio : 图片中X轴方向最大半径
         */
        private int maxImgYRadio, maxImgXRadio;
    
        /**
         * 0 为没有一个步骤通过,且正在进行第一个步骤
         * 1 第一个步骤完成,正在进行第二个步骤
         * 2 第二个步骤完成,正在进行第三个步骤
         * 3 第三个步骤完成,正在进行第四个步骤
         * 4 所有步骤完成
         */
        @Size(min = 0, max = 4)
        private int step = 0;
    
        /**
         * 流程步骤
         */
        private final String[] stepTextContent = {"手机验证", "实名认证", "开通业务", "注册完成"};
        /**
         * 流程步骤文字长度
         */
        private final float[] stepTextLength = new float[stepTextContent.length];
    
        public CertificationProgress(Context context) {
            super(context);
            init(context, null, 0);
        }
    
        public CertificationProgress(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init(context, attrs, 0);
        }
    
        public CertificationProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs, defStyleAttr);
        }
    
        public void init(Context context, AttributeSet attrs, int defStyleAttr) {
    
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CertificationProgress);
    
            textSize = (int) typedArray.getDimension(R.styleable.CertificationProgress_textSize, defaultTextSize);
            textColor = typedArray.getColor(R.styleable.CertificationProgress_textColor, defaultTextColor);
            baseLineColor = typedArray.getColor(R.styleable.CertificationProgress_baseLineColor, defaultBaseLineColor);
    
            typedArray.recycle();
    
            mTextPaint = new TextPaint();
            mTextPaint.setTextSize(textSize);
    
            Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
            textHeight = (int) (fontMetrics.bottom - fontMetrics.top);
            for (int i = 0; i < stepTextContent.length; i++) {
                stepTextLength[i] = mTextPaint.measureText(stepTextContent[i]);
            }
    
            mPaint = new Paint();
    
            certification_finish_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_finish);
            certification_ing_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_ing);
            certification_not_finish_img = BitmapFactory.decodeResource(getResources(), R.drawable.certification_not_finish);
            maxImgYRadio = Math.max(certification_ing_img.getHeight(), Math.max(certification_finish_img.getHeight(), certification_not_finish_img.getHeight())) >> 1;
            maxImgXRadio = Math.max(certification_ing_img.getWidth(), Math.max(certification_not_finish_img.getWidth(), certification_finish_img.getWidth())) >> 1;
    
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            int w = getWidth() - getPaddingLeft() - getPaddingRight() - maxImgXRadio * 2;
            int h = getHeight() - getPaddingTop() - getPaddingBottom();
            canvas.translate(getPaddingLeft() + maxImgXRadio, getPaddingTop());
            drawBaseLine(w, h, canvas);
            drawStepOne(w, h, canvas);
            drawStepTwo(w, h, canvas);
            drawStepThree(w, h, canvas);
            drawStepFour(w, h, canvas);
            drawStepText(w, h, canvas);
        }
    
    
        private void drawStepText(int w, int h, Canvas canvas) {
            Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
            mTextPaint.setColor(textColor);
            for (int i = 0; i < stepTextContent.length; i++) {
                canvas.drawText(stepTextContent[i], i * w / 3.0f - stepTextLength[0] / 2.0f, textHeight * 3 / 2.0f - fontMetrics.bottom, mTextPaint);
            }
        }
    
    
        private void drawBaseLine(int w, int h, Canvas canvas) {
            mPaint.reset();
            mPaint.setColor(baseLineColor);
            canvas.drawLine(0, completeTop(h, null), w, completeTop(h, null), mPaint);
            mPaint.setStrokeWidth(10);
            if (step < 1) return;
            if (step < 2) {
                canvas.drawLine(0, completeTop(h, null), w / 3.0f, completeTop(h, null), mPaint);
            } else if (step < 3) {
                canvas.drawLine(0, completeTop(h, null), w * 2 / 3.0f, completeTop(h, null), mPaint);
            } else {
                canvas.drawLine(0, completeTop(h, null), w, completeTop(h, null), mPaint);
            }
            mPaint.reset();
        }
    
    
        /**
         * 0 为没有一个步骤通过,且正在进行第一个步骤
         * 1 第一个步骤完成,正在进行第二个步骤
         * 2 第二个步骤完成,正在进行第三个步骤
         * 3 第三个步骤完成,正在进行第四个步骤
         * 4 所有步骤完成
         */
        private void drawStepOne(int w, int h, Canvas canvas) {
            if (step < 1) {
                canvas.drawBitmap(certification_ing_img, -maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
            } else {
                canvas.drawBitmap(certification_ing_img, -maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
                canvas.drawBitmap(certification_finish_img, -certification_finish_img.getWidth() / 2.0f, completeTop(h, certification_finish_img), mPaint);
            }
    
        }
    
        private void drawStepTwo(int w, int h, Canvas canvas) {
            if (step < 1) {
                canvas.drawBitmap(certification_not_finish_img, w / 3.0f - certification_not_finish_img.getWidth() / 2.0f, completeTop(h, certification_not_finish_img), mPaint);
            } else if (step < 2) {
                canvas.drawBitmap(certification_ing_img, w / 3.0f - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
            } else {
                canvas.drawBitmap(certification_ing_img, w / 3.0f - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
                canvas.drawBitmap(certification_finish_img, w / 3.0f - certification_finish_img.getWidth() / 2.0f, completeTop(h, certification_finish_img), mPaint);
            }
    
        }
    
        private void drawStepThree(int w, int h, Canvas canvas) {
            if (step < 2) {
                canvas.drawBitmap(certification_not_finish_img, w * 2 / 3.0f - certification_not_finish_img.getWidth() / 2.0f, completeTop(h, certification_not_finish_img), mPaint);
            } else if (step < 3) {
                canvas.drawBitmap(certification_ing_img, w * 2 / 3.0f - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
            } else {
                canvas.drawBitmap(certification_ing_img, w * 2 / 3.0f - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
                canvas.drawBitmap(certification_finish_img, w * 2 / 3.0f - certification_finish_img.getWidth() / 2.0f, completeTop(h, certification_finish_img), mPaint);
            }
    
        }
    
        private void drawStepFour(int w, int h, Canvas canvas) {
            if (step < 3) {
                canvas.drawBitmap(certification_not_finish_img, w - certification_not_finish_img.getWidth() / 2.0f, completeTop(h, certification_not_finish_img), mPaint);
            } else if (step < 4) {
                canvas.drawBitmap(certification_ing_img, w - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
            } else {
                canvas.drawBitmap(certification_ing_img, w - maxImgXRadio, completeTop(h, certification_ing_img), mPaint);
                canvas.drawBitmap(certification_finish_img, w - certification_finish_img.getWidth() / 2.0f, completeTop(h, certification_finish_img), mPaint);
            }
    
        }
    
        private float completeTop(int h, Bitmap bitmap) {
            return (h + textHeight * 2 - (bitmap == null ? 0 : bitmap.getHeight())) / 2.0f;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int setWidth, setHeight;
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
            DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
            if (widthMode == MeasureSpec.EXACTLY) {
                setWidth = measureWidth;
            } else {
                setWidth = displayMetrics.widthPixels;
            }
    
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
            if (heightMode == MeasureSpec.EXACTLY) {
                setHeight = measureHeight;
            } else {
                int h = textHeight * 2 + (maxImgYRadio << 1) + getPaddingTop() + getPaddingBottom();
                setHeight = Math.min(h, measureHeight);
            }
            setMeasuredDimension(setWidth, setHeight);
        }
    
        public void setStep(int step) {
            this.step = step;
            postInvalidate();
        }
    }
    
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值