android 仿摩拜单车共享单车进度条实现StepView

先看效果图:

DbhVozhcEZvQGMfR6Pkc-A33RMAoVqH3kdctdDxLPixJlpnA4otBcw7CSzXkBCt4wE4KU-Ibv9BX-J1um51_2rlzg5dLOr8BQXrgeMpR4B7jzzbyFMI6dNIqRdH51dCi.png

DbhVozhcEZvQGMfR6Pkc-A33RMAoVqH3kdctdDxLPixJlpnA4otBcw7CSzXkBCt4wE4KU-Ibv9BX-J1um51_2um5i7NFsWsi65310NB2fTrgfXMpvrJO_OvuZsH_6LSc.png

Step1:定义StepBean

定义五个状态,分别为:为完成、正在进行、已完成、终点完成、终点未完成。

public class StepBean{
    public static final int STEP_UNDO = -1;//未完成
    public static final int STEP_CURRENT = 0;//正在进行
    public static final int STEP_COMPLETED = 1;//已完成
    public static final int STEP_LAST_COMPLETED = 2;//终点完成
    public static final int STEP_LAST_UNCOMPLETED = 3;//终点未完成
    private String name;
    private int state;

    public String getName(){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }

    public int getState(){
        return state;
    }

    public void setState(int state){
        this.state = state;
    }

    public StepBean(){
    }

    public StepBean(String name, int state){
        this.name = name;
        this.state = state;
    }
}

Step2:自定义HorizontalStepsViewIndicator 

public class HorizontalStepsViewIndicator extends View {
    private int defaultStepIndicatorNum = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, getResources().getDisplayMetrics());//定义默认的高度
    private float mCompletedLineHeight;//完成线的高度
    private float mCircleRadius;//圆的半径

    private Drawable mCompleteIcon;//完成的默认图片
    private Drawable mAttentionIcon;//正在进行的默认图片
    private Drawable mDefaultIcon;//默认的背景图
    private Drawable mLastCompleteIcon;//终点未完成图片
    private Drawable mLastUnCompleteIcon;//终点完成图片

    private float mCenterY;//该view的Y轴中间位置
    private float mLeftY;//左上方的Y位置
    private float mRightY;//右下方的位置

    private List<StepBean> mStepBeanList ;//当前有几步流程
    private int mStepNum = 0;
    private float mLinePadding;//两条连线之间的间距

    private List<Float> mCircleCenterPointPositionList;//定义所有圆的圆心点位置的集合
    private Paint mUnCompletedPaint;//未完成Paint
    private Paint mCompletedPaint;//完成paint
    private int mUnCompletedLineColor = ContextCompat.getColor(getContext(), R.color.uncompleted_color);//定义默认未完成线的颜色
    private int mCompletedLineColor = ContextCompat.getColor(getContext(), R.color.completed_color);//定义默认完成线的颜色
    private PathEffect mEffects;
    private int mComplectingPosition;//正在进行position

    private Path mPath;
    private OnDrawIndicatorListener mOnDrawListener;
    private int screenWidth;

    /**
     * 设置监听
     * @param onDrawListener
     */
    public void setOnDrawListener(OnDrawIndicatorListener onDrawListener){
        mOnDrawListener = onDrawListener;
    }

    /**
     * get圆的半径  get circle radius
     * @return
     */
    public float getCircleRadius(){
        return mCircleRadius;
    }

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

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

    public HorizontalStepsViewIndicator(Context context, AttributeSet attrs, int defStyle){
        super(context, attrs, defStyle);
        init();
    }

    private void init(){
        mStepBeanList = new ArrayList<>();
        mPath = new Path();
        mEffects = new DashPathEffect(new float[]{8, 8, 8, 8}, 1);
        mCircleCenterPointPositionList = new ArrayList<>();//初始化

        mUnCompletedPaint = new Paint();
        mCompletedPaint = new Paint();
        mUnCompletedPaint.setAntiAlias(true);
        mUnCompletedPaint.setColor(mUnCompletedLineColor);
        mUnCompletedPaint.setStyle(Paint.Style.STROKE);
        mUnCompletedPaint.setStrokeWidth(2);
        mCompletedPaint.setAntiAlias(true);
        mCompletedPaint.setColor(mCompletedLineColor);
        mCompletedPaint.setStyle(Paint.Style.STROKE);
        mCompletedPaint.setStrokeWidth(2);
        mUnCompletedPaint.setPathEffect(mEffects);
        mCompletedPaint.setStyle(Paint.Style.FILL);

        mCompletedLineHeight = 0.03f * defaultStepIndicatorNum;//已经完成线的宽高
        mCircleRadius = 0.28f * defaultStepIndicatorNum;//圆的半径
        mLinePadding = 1.0f * defaultStepIndicatorNum;//线与线之间的间距

        mCompleteIcon = ContextCompat.getDrawable(getContext(), R.drawable.complted);//已经完成的icon
        mAttentionIcon = ContextCompat.getDrawable(getContext(), R.drawable.attention);//正在进行的icon
        mDefaultIcon = ContextCompat.getDrawable(getContext(), R.drawable.default_icon);//未完成的icon
        mLastCompleteIcon= ContextCompat.getDrawable(getContext(), R.drawable.last_complted);//终点已完成的icon
        mLastUnCompleteIcon= ContextCompat.getDrawable(getContext(), R.drawable.last_uncomplted);//终点未完成的icon
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        int width = defaultStepIndicatorNum * 2;
        if(MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec)){
            screenWidth = MeasureSpec.getSize(widthMeasureSpec);
        }
        int height = defaultStepIndicatorNum;
        if(MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec)){
            height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
        }
        width = (int) (mStepNum * mCircleRadius * 2 - (mStepNum - 1) * mLinePadding);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh){
        super.onSizeChanged(w, h, oldw, oldh);
        //获取中间的高度,目的是为了让该view绘制的线和圆在该view垂直居中
        mCenterY = 0.5f * getHeight();
        //获取左上方Y的位置,获取该点的意义是为了方便画矩形左上的Y位置
        mLeftY = mCenterY - (mCompletedLineHeight / 2);
        //获取右下方Y的位置,获取该点的意义是为了方便画矩形右下的Y位置
        mRightY = mCenterY + mCompletedLineHeight / 2;

        mCircleCenterPointPositionList.clear();
        for(int i = 0; i < mStepNum; i++){
            //先计算全部最左边的padding值(getWidth()-(圆形直径+两圆之间距离)*2)
            float paddingLeft = (screenWidth - mStepNum * mCircleRadius * 2 - (mStepNum - 1) * mLinePadding) / 2;
            //add to list
            mCircleCenterPointPositionList.add(paddingLeft + mCircleRadius + i * mCircleRadius * 2 + i * mLinePadding);
        }

        /**
         * set listener
         */
        if(mOnDrawListener!=null){
            mOnDrawListener.ondrawIndicator();
        }
    }

    @Override
    protected synchronized void onDraw(Canvas canvas){
        super.onDraw(canvas);
        if(mOnDrawListener!=null){
            mOnDrawListener.ondrawIndicator();
        }
        mUnCompletedPaint.setColor(mUnCompletedLineColor);
        mCompletedPaint.setColor(mCompletedLineColor);
        //-----------------------画线-------draw line-----------------------------------------------
        for(int i = 0; i < mCircleCenterPointPositionList.size() -1; i++){
            //前一个ComplectedXPosition
            final float preComplectedXPosition = mCircleCenterPointPositionList.get(i);
            //后一个ComplectedXPosition
            final float afterComplectedXPosition = mCircleCenterPointPositionList.get(i + 1);
            if(i <= mComplectingPosition&&mStepBeanList.get(0).getState()!=StepBean.STEP_UNDO){//判断在完成之前的所有点
                //判断在完成之前的所有点,画完成的线,这里是矩形,很细的矩形,类似线,为了做区分,好看些
                canvas.drawRect(preComplectedXPosition + mCircleRadius - 10, mLeftY, afterComplectedXPosition - mCircleRadius + 10, mRightY, mCompletedPaint);
            } else{
                mPath.moveTo(preComplectedXPosition + mCircleRadius, mCenterY);
                mPath.lineTo(afterComplectedXPosition - mCircleRadius, mCenterY);
                canvas.drawPath(mPath, mUnCompletedPaint);
            }
        }
        //-----------------------画线-------draw line-----------------------------------------------

        //-----------------------画图标-----draw icon-----------------------------------------------
        for(int i = 0; i < mCircleCenterPointPositionList.size(); i++){
            final float currentComplectedXPosition = mCircleCenterPointPositionList.get(i);
            Rect rect = new Rect((int) (currentComplectedXPosition - mCircleRadius), (int) (mCenterY - mCircleRadius), (int) (currentComplectedXPosition + mCircleRadius), (int) (mCenterY + mCircleRadius));
            StepBean stepsBean = mStepBeanList.get(i);
            if(stepsBean.getState()==StepBean.STEP_UNDO){
                mDefaultIcon.setBounds(rect);
                mDefaultIcon.draw(canvas);
            }else if(stepsBean.getState()==StepBean.STEP_CURRENT){
                mCompletedPaint.setColor(Color.WHITE);
                canvas.drawCircle(currentComplectedXPosition, mCenterY, mCircleRadius * 1.1f, mCompletedPaint);
                mAttentionIcon.setBounds(rect);
                mAttentionIcon.draw(canvas);
            }else if(stepsBean.getState()==StepBean.STEP_COMPLETED){
                mCompleteIcon.setBounds(rect);
                mCompleteIcon.draw(canvas);
            }else if(stepsBean.getState()==StepBean.STEP_LAST_COMPLETED){
                mLastCompleteIcon.setBounds(rect);
                mLastCompleteIcon.draw(canvas);
            }else if(stepsBean.getState()==StepBean.STEP_LAST_UNCOMPLETED){
                mLastUnCompleteIcon.setBounds(rect);
                mLastUnCompleteIcon.draw(canvas);
            }
        }
        //-----------------------画图标-----draw icon-----------------------------------------------
    }

    /**
     * 得到所有圆点所在的位置
     * @return
     */
    public List<Float> getCircleCenterPointPositionList()
    {
        return mCircleCenterPointPositionList;
    }

    /**
     * 设置流程步数
     * @param stepsBeanList 流程步数
     */
    public void setStepNum(List<StepBean> stepsBeanList) {
        this.mStepBeanList = stepsBeanList;
        mStepNum = mStepBeanList.size();

        if(mStepBeanList!=null&&mStepBeanList.size()>0){
            for(int i = 0;i<mStepNum;i++){
                StepBean stepsBean = mStepBeanList.get(i);
                    if(stepsBean.getState()==StepBean.STEP_COMPLETED){
                        mComplectingPosition = i;
                    }
            }
        }
        requestLayout();
    }

    /**
     * 设置未完成线的颜色
     * @param unCompletedLineColor
     */
    public void setUnCompletedLineColor(int unCompletedLineColor){
        this.mUnCompletedLineColor = unCompletedLineColor;
    }

    /**
     * 设置已完成线的颜色
     * @param completedLineColor
     */
    public void setCompletedLineColor(int completedLineColor){
        this.mCompletedLineColor = completedLineColor;
    }

    /**
     * 设置默认图片
     * @param defaultIcon
     */
    public void setDefaultIcon(Drawable defaultIcon){
        this.mDefaultIcon = defaultIcon;
    }

    /**
     * 设置已完成图片
     * @param completeIcon
     */
    public void setCompleteIcon(Drawable completeIcon){
        this.mCompleteIcon = completeIcon;
    }

    public void setLastCompleteIcon(Drawable lastcompleteIcon){
        this.mLastCompleteIcon = lastcompleteIcon;
    }

    public void setLastUnCompleteIcon(Drawable lastUnCompleteIcon){
        this.mLastUnCompleteIcon = lastUnCompleteIcon;
    }

    /**
     * 设置正在进行中的图片
     * @param attentionIcon
     */
    public void setAttentionIcon(Drawable attentionIcon){
        this.mAttentionIcon = attentionIcon;
    }

    /**
     * 设置对view监听
     */
    public interface OnDrawIndicatorListener{
        void ondrawIndicator();
    }
}

Step3:自定义HorizontalStepView 

public class HorizontalStepView extends LinearLayout implements HorizontalStepsViewIndicator.OnDrawIndicatorListener{
    private RelativeLayout mTextContainer;
    private HorizontalStepsViewIndicator mStepsViewIndicator;
    private List<StepBean> mStepBeanList;
    private int mComplectingPosition;
    private int mUnComplectedTextColor = ContextCompat.getColor(getContext(), R.color.uncompleted_text_color);//定义默认未完成文字的颜色;
    private int mComplectedTextColor = ContextCompat.getColor(getContext(), R.color.completed_color);//定义默认完成文字的颜色;
    private int mTextSize = 14;//default textSize
    private TextView mTextView;

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

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

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

    private void init(){
        View rootView = LayoutInflater.from(getContext()).inflate(R.layout.widget_horizontal_stepsview, this);
        mStepsViewIndicator = (HorizontalStepsViewIndicator) rootView.findViewById(R.id.steps_indicator);
        mStepsViewIndicator.setOnDrawListener(this);
        mTextContainer = (RelativeLayout) rootView.findViewById(R.id.rl_text_container);
    }

    /**
     * 设置显示的文字
     * @param stepsBeanList
     * @return
     */
    public HorizontalStepView setStepViewTexts(List<StepBean> stepsBeanList) {
        mStepBeanList = stepsBeanList;
        mStepsViewIndicator.setStepNum(mStepBeanList);
        return this;
    }


    /**
     * 设置未完成文字的颜色
     * @param unComplectedTextColor
     * @return
     */
    public HorizontalStepView setStepViewUnComplectedTextColor(int unComplectedTextColor) {
        mUnComplectedTextColor = unComplectedTextColor;
        return this;
    }

    /**
     * 设置完成文字的颜色
     * @param complectedTextColor
     * @return
     */
    public HorizontalStepView setStepViewComplectedTextColor(int complectedTextColor) {
        this.mComplectedTextColor = complectedTextColor;
        return this;
    }

    /**
     * 设置StepsViewIndicator未完成线的颜色
     * @param unCompletedLineColor
     * @return
     */
    public HorizontalStepView setStepsViewIndicatorUnCompletedLineColor(int unCompletedLineColor) {
        mStepsViewIndicator.setUnCompletedLineColor(unCompletedLineColor);
        return this;
    }

    /**
     * 设置StepsViewIndicator完成线的颜色
     * @param completedLineColor
     * @return
     */
    public HorizontalStepView setStepsViewIndicatorCompletedLineColor(int completedLineColor) {
        mStepsViewIndicator.setCompletedLineColor(completedLineColor);
        return this;
    }

    /**
     * 设置StepsViewIndicator默认图片
     * @param defaultIcon
     */
    public HorizontalStepView setStepsViewIndicatorDefaultIcon(Drawable defaultIcon) {
        mStepsViewIndicator.setDefaultIcon(defaultIcon);
        return this;
    }

    /**
     * 设置StepsViewIndicator已完成图片
     * @param completeIcon
     */
    public HorizontalStepView setStepsViewIndicatorCompleteIcon(Drawable completeIcon) {
        mStepsViewIndicator.setCompleteIcon(completeIcon);
        return this;
    }

    /**
     * 设置StepsViewIndicator正在进行中的图片
     * @param attentionIcon
     */
    public HorizontalStepView setStepsViewIndicatorAttentionIcon(Drawable attentionIcon) {
        mStepsViewIndicator.setAttentionIcon(attentionIcon);
        return this;
    }

    public HorizontalStepView setStepsViewIndicatorLastCompleteIcon(Drawable lastCompleteIcon) {
        mStepsViewIndicator.setLastCompleteIcon(lastCompleteIcon);
        return this;
    }

    public HorizontalStepView setStepsViewIndicatorLastUnCompleteIcon(Drawable lastUnCompleteIcon) {
        mStepsViewIndicator.setLastUnCompleteIcon(lastUnCompleteIcon);
        return this;
    }

    /**
     * set textSize
     * @param textSize
     * @return
     */
    public HorizontalStepView setTextSize(int textSize) {
        if(textSize > 0) {
            mTextSize = textSize;
        }
        return this;
    }

    @Override
    public void ondrawIndicator() {
        if(mTextContainer != null) {
            mTextContainer.removeAllViews();
            List<Float> complectedXPosition = mStepsViewIndicator.getCircleCenterPointPositionList();
            if(mStepBeanList != null && complectedXPosition != null && complectedXPosition.size() > 0) {
                for(int i = 0; i < mStepBeanList.size(); i++) {
                    mTextView = new TextView(getContext());
                    mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSize);
                    mTextView.setText(mStepBeanList.get(i).getName());
                    int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                    mTextView.measure(spec, spec);
                    // getMeasuredWidth
                    int measuredWidth = mTextView.getMeasuredWidth();
                    mTextView.setX(complectedXPosition.get(i) - measuredWidth / 2);
                    mTextView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

                    if(i <= mComplectingPosition) {
                        mTextView.setTypeface(null);
                        mTextView.setTextColor(mComplectedTextColor);
                    } else{
                        mTextView.setTextColor(mUnComplectedTextColor);
                    }
                    mTextContainer.addView(mTextView);
                }
            }
        }
    }
}

Step4:如何使用?

在布局文件xml中:

<cn.comnav.utrain.ui.widget.HorizontalStepView
                    android:id="@+id/hsv_step_view"
                    android:layout_width="match_parent"
                    android:layout_height="80dp"
                    android:layout_below="@+id/ll_role"
                    android:layout_marginBottom="40dp"
                    />

在Activity中的使用,部分代码截取:

private List<StepBean> stepsBeanList;
                  private HorizontalStepView mHorizontalStepView;
                  mHorizontalStepView=(HorizontalStepView)findViewById(R.id.hsv_step_view);

                  stepsBeanList = new ArrayList<>();
                        StepBean stepBean0=null;
                        StepBean stepBean1=null;
                        StepBean stepBean2=null;
                        StepBean stepBean3=null;
                        switch (stepIndex){
                            case 1:
                                stepBean0 = new StepBean("手机绑定",1);
                                stepBean1 = new StepBean("实名认证",0);
                                stepBean2 = new StepBean("学时充值",-1);
                                stepBean3 = new StepBean("开始用车",3);
                                break;
                            case 2:
                                stepBean0 = new StepBean("手机绑定",1);
                                stepBean1 = new StepBean("实名认证",1);
                                stepBean2 = new StepBean("学时充值",0);
                                stepBean3 = new StepBean("开始用车",3);
                                break;
                            case 3:
                                stepBean0 = new StepBean("手机绑定",1);
                                stepBean1 = new StepBean("实名认证",1);
                                stepBean2 = new StepBean("学时充值",1);
                                stepBean3 = new StepBean("开始用车",2);
                                break;
                        }
                        stepsBeanList.add(stepBean0);
                        stepsBeanList.add(stepBean1);
                        stepsBeanList.add(stepBean2);
                        stepsBeanList.add(stepBean3);
                    mHorizontalStepView.setStepViewTexts(stepsBeanList);

如果此文对您有帮助,微信打赏一下吧~

DbhVozhcEZvQGMfR6Pkc-A33RMAoVqH3kdctdDxLPixJlpnA4otBcw7CSzXkBCt4wE4KU-Ibv9BX-J1um51_2liN_8fWhgqWosdayhLl79z6_3tLTAsWcOMj3wn0hnUL.jpg