天天看點

【Android】繪制流程節點圖StepView

1、MyStepInfoBean.java

每個節點樣式

package com.dj.processindication.StepView;


public class MyStepInfoBean {
    private String name;
    private Enum status;

    public MyStepInfoBean(String name, Enum status) {
        this.name = name;
        this.status = status;
    }

    public enum StepStatus {
        COMPLETED,UNCOMPLETED,COMPLETING
    }

    public String getName() {
        return name;
    }

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

    public Enum getStatus() {
        return status;
    }

    public void setStatus(Enum status) {
        this.status = status;
    }
}
           

2、StepView.java

繪制所有節點

package com.dj.processindication.StepView;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import com.dj.processindication.R;

import java.util.ArrayList;
import java.util.List;


public class StepView extends View {

    private static final int DEFAULT_RADIU = 35;
    private static final int DEFAULT_LINE_HEIGHT = 120;
    private static final int DEFAULT_DASH_PADDING = 6;
    private static final int DEFAULT_DASH_HEIGHT = 15;
    private static final int ORIENTATION_VERTICAL = 0;
    private static final int ORIENTATION_HORIZONTAL = 1;
    private static final int DEFAULT_COMPLETED_DRAWABLE_ID = R.drawable.circledone;
    private static final int DEFAULT_UNCOMPLETED_DRAWABLE_ID = R.drawable.circlenotdo;
    private static final int DEFAULT_COMPLETING_DRAWABLE_ID = R.drawable.circledoing;

    private int mRadiu;
    private int mLineLength;
    private int mDashPadding;
    private int mDashLength;
    private int mOrientation;
    private int mCompletedDrawableResourceId;
    private int mUncompletedDrawableResourceId;
    private int mCompletingDrawableResourceId;

    private Bitmap mIconCompleted;
    private Bitmap mIconCompleting;
    private Bitmap mIconUncompleted;
    private Paint mCompletePaint;
    private Paint mUnCompleted;
    private List<MyStepInfoBean> mData = new ArrayList<>();
    private int mWidth;
    private int mHeight;
    private Rect mCheckRect;
    private Rect mExclamationMarkRect;
    private Rect mCircleRect;
    private Paint mIconPaint;

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

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

    public StepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.StepView);
        mRadiu = typedArray.getInt(R.styleable.StepView_radius, DEFAULT_RADIU);
        mLineLength = typedArray.getInt(R.styleable.StepView_line_height, DEFAULT_LINE_HEIGHT);
        mDashPadding = typedArray.getInt(R.styleable.StepView_dash_padding, DEFAULT_DASH_PADDING);
        mDashLength = typedArray.getInt(R.styleable.StepView_dash_height, DEFAULT_DASH_HEIGHT);
        mOrientation = typedArray.getInt(R.styleable.StepView_orientation, ORIENTATION_HORIZONTAL);
        mCompletedDrawableResourceId = typedArray.getResourceId(R.styleable.StepView_icon_completed,DEFAULT_COMPLETED_DRAWABLE_ID);
        mUncompletedDrawableResourceId = typedArray.getResourceId(R.styleable.StepView_icon_uncompleted,DEFAULT_UNCOMPLETED_DRAWABLE_ID);
        mCompletingDrawableResourceId = typedArray.getResourceId(R.styleable.StepView_icon_completing,DEFAULT_COMPLETING_DRAWABLE_ID);
        typedArray.recycle();
        init();
    }

    private void init() {
        mIconCompleted = BitmapFactory.decodeResource(getResources(), mCompletedDrawableResourceId);
        mIconCompleting = BitmapFactory.decodeResource(getResources(), mCompletingDrawableResourceId);
        mIconUncompleted = BitmapFactory.decodeResource(getResources(), mUncompletedDrawableResourceId);
        mIconPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mIconPaint.setStyle(Paint.Style.FILL);
        mCompletePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCompletePaint.setColor(0xFF106382);
        mCompletePaint.setStrokeWidth(5);
        mCompletePaint.setTextSize(30);
        mUnCompleted = new Paint(Paint.ANTI_ALIAS_FLAG);
        mUnCompleted.setColor(0xFFdbdbdb);
        mUnCompleted.setStrokeWidth(5);

        mCheckRect = new Rect(0, 0, mIconCompleted.getWidth(), mIconCompleted.getHeight());
        mExclamationMarkRect = new Rect(0, 0, mIconCompleting.getWidth(), mIconCompleting.getHeight());
        mCircleRect = new Rect(0, 0, mIconUncompleted.getWidth(), mIconUncompleted.getHeight());
    }

    public void setData(List<MyStepInfoBean> data) {
        if (data == null || data.size() == 0) {
            return;
        }
        mData = data;

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mData == null || mData.size() == 0) {
            return;
        }
        int centerIndex = mData.size() % 2 != 0 ? (int) Math.ceil(mData.size() / 2.0f) - 1 : mData.size() / 2 - 1;
        for (int i = 0; i < mData.size(); i++) {
            MyStepInfoBean item = mData.get(i);
            int centerX = (mOrientation == ORIENTATION_HORIZONTAL ? mWidth : mHeight) / 2;
            int centerY = (mOrientation == ORIENTATION_HORIZONTAL ? mHeight : mWidth) / 2;
            int bitmapCenter = mData.size() % 2 != 0 ? centerX - (centerIndex - i) * (mLineLength + mRadiu * 2) : (int) (centerX - (centerIndex - i + 0.5) * (mLineLength + mRadiu * 2));
            Rect srcBitmapRect = mOrientation == ORIENTATION_HORIZONTAL ? new Rect(bitmapCenter - mRadiu, centerY - mRadiu, bitmapCenter + mRadiu, centerY + mRadiu) :
                    new Rect(centerY - mRadiu, bitmapCenter - mRadiu, centerY + mRadiu, bitmapCenter + mRadiu);
            canvas.drawBitmap(item.getStatus() == MyStepInfoBean.StepStatus.COMPLETED ? mIconCompleted :
                    item.getStatus() == MyStepInfoBean.StepStatus.COMPLETING ? mIconCompleting :
                            mIconUncompleted, item.getStatus() == MyStepInfoBean.StepStatus.COMPLETED ? mCheckRect :
                    item.getStatus() == MyStepInfoBean.StepStatus.COMPLETING ? mExclamationMarkRect :
                            mCircleRect, srcBitmapRect, mIconPaint);
            float v = mCompletePaint.measureText(item.getName());
            if (mOrientation == ORIENTATION_HORIZONTAL) {
                canvas.drawText(item.getName(), bitmapCenter - v / 2, centerY + mRadiu * 2, mCompletePaint);
            } else {
                canvas.drawText(item.getName(), centerY + mRadiu * 2, bitmapCenter, mCompletePaint);
            }

            if (i < mData.size() - 1) {
                int lineLeft = mData.size() % 2 != 0 ? (int) (centerX - (centerIndex - i) * mLineLength - (centerIndex - i - 0.5) * mRadiu * 2) : (int) (centerX - (centerIndex - i + 0.5) * mLineLength - (centerIndex - i) * mRadiu * 2);
                if (mData.get(i + 1).getStatus() == MyStepInfoBean.StepStatus.UNCOMPLETED) {
                    for (int j = 0; j < 6; j++) {
                        if (mOrientation == ORIENTATION_HORIZONTAL) {
                            canvas.drawLine(lineLeft + (mDashLength + mDashPadding) * j, centerY - 2, lineLeft + mDashLength * (j + 1) + mDashPadding * j, centerY - 2, mUnCompleted);
                        } else {
                            canvas.drawLine(centerY - 2, lineLeft + (mDashLength + mDashPadding) * j, centerY - 2, lineLeft + mDashLength * (j + 1) + mDashPadding * j, mUnCompleted);
                        }
                    }
                } else {
                    if (mOrientation == ORIENTATION_HORIZONTAL) {
                        canvas.drawLine(lineLeft, centerY , lineLeft + mLineLength, centerY , mCompletePaint);
                    } else {
                        canvas.drawLine(centerY - 2, lineLeft, centerY - 2, lineLeft + mLineLength, mCompletePaint);
                    }
                }
            }
        }
    }
}
           

3、CurrentState.java

業務層面的工具類

package com.dj.processindication.StepView;

import java.util.ArrayList;

public class CurrentState {
    private ArrayList<MyStepInfoBean> mCurrentStep = new ArrayList<>();
    private StepView mStepView;


    public CurrentState(StepView stepView) {
        this.mStepView = stepView;
        initData();
    }


    private void initData() {
        setStepViewNone();
    }

    public void setCurrentState(int i){
        switch(i){
            case 0:
                setStepView0();
                break;
            case 1:
                setStepView1();
                break;
            case 2:
                setStepView2();
                break;
            case 3:
                setStepView3();
                break;
            case 4:
                setStepView4();
                break;
        }
    }

    private void setData() {
        mStepView.setData(mCurrentStep);
    }

    private void setStepViewNone(){
        mCurrentStep.clear();
        mCurrentStep.add(new MyStepInfoBean("步驟1",MyStepInfoBean.StepStatus.UNCOMPLETED));//0
        mCurrentStep.add(new MyStepInfoBean("步驟2",MyStepInfoBean.StepStatus.UNCOMPLETED));//1
        mCurrentStep.add(new MyStepInfoBean("步驟3",MyStepInfoBean.StepStatus.UNCOMPLETED));//2
        mCurrentStep.add(new MyStepInfoBean("步驟4",MyStepInfoBean.StepStatus.UNCOMPLETED));//3
        mCurrentStep.add(new MyStepInfoBean("步驟5",MyStepInfoBean.StepStatus.UNCOMPLETED));//4
        setData();
    }

    private void setStepView0(){
        mCurrentStep.clear();
        mCurrentStep.add(new MyStepInfoBean("步驟1",MyStepInfoBean.StepStatus.COMPLETED));//0
        mCurrentStep.add(new MyStepInfoBean("步驟2",MyStepInfoBean.StepStatus.UNCOMPLETED));//1
        mCurrentStep.add(new MyStepInfoBean("步驟3",MyStepInfoBean.StepStatus.UNCOMPLETED));//2
        mCurrentStep.add(new MyStepInfoBean("步驟4",MyStepInfoBean.StepStatus.UNCOMPLETED));//3
        mCurrentStep.add(new MyStepInfoBean("步驟5",MyStepInfoBean.StepStatus.UNCOMPLETED));//4
        setData();
    }

}
           

4、activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".MainActivity">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <com.dj.processindication.StepView.StepView
            android:id="@+id/sv_currentState"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:icon_completed="@drawable/circledone"
            app:icon_uncompleted="@drawable/circlenotdo"
            app:icon_completing="@drawable/circledoing"
            />

    </LinearLayout>
</LinearLayout>
           

5、attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="StepView">
        <attr name="radius" format="integer"/>
        <attr name="line_height" format="integer"/>
        <attr name="dash_padding" format="integer"/>
        <attr name="dash_height" format="integer"/>
        <attr name="orientation">
            <enum name="vertical" value="0"/>
            <enum name="horizontal" value="1"/>
        </attr>
        <attr name="icon_completed" format="reference"/>
        <attr name="icon_uncompleted" format="reference"/>
        <attr name="icon_completing" format="reference"/>
    </declare-styleable>
</resources>
           

6、MainActivity

package com.dj.processindication;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

import com.dj.processindication.StepView.CurrentState;
import com.dj.processindication.StepView.StepView;

public class MainActivity extends AppCompatActivity {


    private StepView mStepView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mStepView = (StepView) findViewById(R.id.sv_currentState);
        CurrentState mCurrentState = new CurrentState(mStepView);
        mCurrentState.setCurrentState(2);
    }

}