android自定義view--步驟(進度)stepview

先上效果圖,如果這是你想要的效果可以往下看。不是的話也可以借鑑一下。

1、自定義view的基本流程

1)measure();

主要作用是測量view的寬高

2)layout();

主要作用是計算子view的位置,一般是自定義viewgroup時纔會用上。(這裏可以忽略)

3)draw();

主要作用是繪製view,切記由於該方法會多次執行,切勿在這個方法裏面過多的創建對象,以免引起內存泄漏。

2、核心思想

1)從效果圖可以看出stepview是有多個步驟的,那麼我們可以使用stepbean來封裝每一步的屬性值。具體內容如下:

/**
 * 步驟view的數據基類
 */
public class StepBean {
    private String name;
    private String time;
    private int icon;//圖片icon
    private int lineColor;
    private int nameColor;
    private int timeColor;
    private boolean isIng = false;

    public String getName() {
        return name;
    }

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

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public int getIcon() {
        return icon;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

    public int getLineColor() {
        return lineColor;
    }

    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
    }

    public boolean isIng() {
        return isIng;
    }

    public void setIng(boolean ing) {
        isIng = ing;
    }

    public int getTimeColor() {
        return timeColor;
    }

    public void setTimeColor(int timeColor) {
        this.timeColor = timeColor;
    }

    public int getNameColor() {
        return nameColor;
    }

    public void setNameColor(int nameColor) {
        this.nameColor = nameColor;
    }
}

2)stepview會傳入一個List<StepBean>來決定繪製多少步。下面我們來看看具體實現:代碼裏面的註解也很詳細,無非是畫圓畫線和繪製圖片。

/**
 * 自定義步驟view
 */
public class StepView extends View {

    /**
     * 需要顯示的步驟節點集合
     */
    private List<StepBean> stepBeanList = new ArrayList<>();
    private int mCurrViewWidth;//當前控件寬度
    private int mCurrViewHeight;//當前控件高度

    private Paint mPaint;//節點畫筆
    private TextPaint mTextPaint;//文字描述的畫筆
    private Paint mLinePaint;
    private int roundSize = 8;//圓的直徑
    private int haloRoundSize = 0;//外圓的直徑
    private int haloThickness = 1;//外圓的厚度
    private int haloAlpha = 50;//光暈透明度
    private int haloWidth = 4;//光暈的寬度
    private int textSize = 12;//文字大小
    private int lineHeight = 1;//步驟線的高度
    private int startX = 0;//X軸開始位置
    private int startY = 10;//Y軸開始位置
    private int itemWidth = 0;//每一項的寬度
    private int roundType = 0;//0空心圓,2光暈圓
    //所有位置以圓心爲標準
    private int roundX = 0;//大圓心X
    private int roundY = 0;//大圓心Y
    private int bigRoundSize = 20;//圓的直徑

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

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

    private void init(Context context) {
        //dp轉px
        roundSize = DensityUtil.dip2px(context, roundSize);
        haloWidth = DensityUtil.dip2px(context, haloWidth);
        haloRoundSize = roundSize + haloWidth * 2;
        bigRoundSize = DensityUtil.dip2px(context, bigRoundSize);
        roundY = DensityUtil.dip2px(context, startY) + bigRoundSize / 2;
        haloThickness = DensityUtil.dip2px(context, haloThickness);
        lineHeight = DensityUtil.dip2px(context, lineHeight);
        textSize = DensityUtil.dip2px(context, textSize);

        mPaint = new Paint();
        mPaint.setAntiAlias(true); //消除鋸齒
        mLinePaint = new Paint();
        //線高
        mLinePaint.setStrokeWidth(lineHeight);
        //虛線
        DashPathEffect effects = new DashPathEffect(new float[]{lineHeight * 3,
                lineHeight * 3}, 0);
        mLinePaint.setPathEffect(effects);
        mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true); //消除鋸齒
        mTextPaint.setTextSize(textSize);
        mTextPaint.setTypeface(Typeface.SANS_SERIF);
        //文字字體加粗
        mTextPaint.setFakeBoldText(false);

    }

    public void setStepBeanList(List<StepBean> stepBeanList) {
        if (stepBeanList != null)
            this.stepBeanList = stepBeanList;
        //計算控件開始位置
        if (stepBeanList.size() > 0)
            itemWidth = mCurrViewWidth / stepBeanList.size();
        roundX = itemWidth / 2 - bigRoundSize / 2;
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mCurrViewWidth = getMeasuredWidth();
        mCurrViewHeight = getMeasuredHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < stepBeanList.size(); i++) {
            // 畫圓
            mPaint.setColor(stepBeanList.get(i).getLineColor());
            mPaint.setStyle(Paint.Style.FILL); //繪製實心圓
            RectF rf2 = new RectF(roundX - roundSize / 2 + itemWidth * i, roundY - roundSize / 2, roundX + roundSize / 2 + itemWidth * i, roundY + roundSize / 2);
            canvas.drawOval(rf2, mPaint);
            if (roundType == 0) {
                // 畫空心圓
                mPaint.setStyle(Paint.Style.STROKE); //繪製空心圓
                mPaint.setStrokeWidth(haloThickness);//設置空心圓的厚度
            } else {
                // 畫圓光圈
                mPaint.setAlpha(haloAlpha);
            }
            RectF haloRectF = new RectF(roundX - haloRoundSize / 2 + itemWidth * i, roundY - haloRoundSize / 2, roundX + haloRoundSize / 2 + itemWidth * i, roundY + haloRoundSize / 2);
            canvas.drawOval(haloRectF, mPaint);
            // 繪製線,最後一個點不用繪製線
            if (i < stepBeanList.size() - 1) {
                mLinePaint.setColor(stepBeanList.get(i + 1).getLineColor());
                int x = roundX + haloRoundSize / 2;//開始位置
                canvas.drawLine(x + itemWidth * i, roundY, x + itemWidth * (i + 1) - haloRoundSize, roundY, mLinePaint);
            }
            //繪製正在進行的圖片
            if (stepBeanList.get(i).isIng()) {
                Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), stepBeanList.get(i).getIcon());
                int w = mBitmap.getWidth();
                int h = mBitmap.getHeight();
                // 指定圖片繪製區域(全圖)
                Rect src = new Rect(0, 0, w, h);
                // 指定圖片在屏幕上顯示的區域(原圖大小)
                Rect dst = new Rect(roundX - w / 2 + itemWidth * i, roundY - h / 2, roundX + w / 2 + itemWidth * i, roundY + h / 2);
                canvas.drawBitmap(mBitmap, src, dst, null);
            }
            // 繪製name文字
            mTextPaint.setColor(stepBeanList.get(i).getNameColor());
            int tx = roundX - getTextWidth(stepBeanList.get(i).getName(), mTextPaint) / 2 + itemWidth * i;
            int ty = roundY + bigRoundSize + getTextHeight(stepBeanList.get(i).getName(), mTextPaint);
            canvas.drawText(stepBeanList.get(i).getName(), tx, ty, mTextPaint);
            // 繪製time文字
            mTextPaint.setColor(stepBeanList.get(i).getTimeColor());
            tx = roundX - getTextWidth(stepBeanList.get(i).getTime(), mTextPaint) / 2 + itemWidth * i;
            ty = ty + getTextHeight(stepBeanList.get(i).getTime(), mTextPaint) * 2;
            canvas.drawText(stepBeanList.get(i).getTime(), tx, ty, mTextPaint);
        }
    }

    //獲取文字寬度
    private int getTextWidth(String text, Paint paint) {
        Rect rect = new Rect(); // 文字所在區域的矩形
        paint.getTextBounds(text, 0, text.length(), rect);
        return rect.width();
    }

    //獲取文字高度
    private int getTextHeight(String text, Paint paint) {
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return rect.height();
    }
}

3)這裏需要注意一下,由於我這邊的需求的步驟不多,所以我這邊是按:屏幕的寬度/步驟總數 = 每一步的寬度;如果你的步驟過多的話會出現每一步的寬度很小,可以考慮採用滑動顯示的方式來實現。

3、如何使用:

1)在佈局頁面編寫以下代碼:

<com.library_base.ui.view.stepview.StepView
                            android:id="@+id/stepView"
                            android:layout_width="match_parent"
                            android:layout_height="80dp"/>

2)在Activity裏面使用:

StepView stepView = findViewById(R.id.stepView);

private void setStepBean(String type) {
        List<StepBean> stepBeans = new ArrayList<>();
        //待覈銷
        StepBean stepBean = new StepBean();
        stepBean.setName("待覈銷");
        stepBean.setTime(CommonUtils.getDateToString2(Long.parseLong(detailObject.getOrderTime())));
        stepBean.setNameColor(Color.parseColor("#333333"));
        stepBean.setTimeColor(Color.parseColor("#CCCCCC"));
        stepBean.setLineColor(Color.parseColor("#51B3F1"));
        stepBeans.add(stepBean);
        //覈銷中
        stepBean = new StepBean();
        stepBean.setName("覈銷中");
        stepBean.setTime(CommonUtils.getDateToString2(Long.parseLong(detailObject.getOrderTime())));
        stepBean.setLineColor(Color.parseColor("#51B3F1"));
        stepBean.setTimeColor(Color.parseColor("#CCCCCC"));
        if (type.equals("0")) {
            stepBean.setNameColor(Color.parseColor("#51B3F1"));
            stepBean.setIng(true);
            stepBean.setIcon(R.mipmap.check_state_img);
        } else {
            stepBean.setNameColor(Color.parseColor("#333333"));
        }
        stepBeans.add(stepBean);
        //覈銷完成
        stepBean = new StepBean();
        stepBean.setTimeColor(Color.parseColor("#CCCCCC"));
        if (type.equals("0")) {
            stepBean.setName("覈銷完成");
            stepBean.setTime("");
            stepBean.setNameColor(Color.parseColor("#333333"));
            stepBean.setLineColor(Color.parseColor("#D8D8D8"));
        } else if (type.equals("1")) {
            //覈銷不通過
            stepBean.setName("覈銷不通過");
            stepBean.setTime(CommonUtils.getDateToString2(Long.parseLong(detailObject.getVerificationTime())));
            stepBean.setNameColor(Color.parseColor("#FF4503"));
            stepBean.setLineColor(Color.parseColor("#FF4503"));
            stepBean.setIng(true);
            stepBean.setIcon(R.mipmap.check_state_un);
        } else if (type.equals("2")) {
            //覈銷通過
            stepBean.setName("覈銷通過");
            stepBean.setTime(CommonUtils.getDateToString2(Long.parseLong(detailObject.getVerificationTime())));
            stepBean.setNameColor(Color.parseColor("#51B3F1"));
            stepBean.setLineColor(Color.parseColor("#51B3F1"));
            stepBean.setIng(true);
            stepBean.setIcon(R.mipmap.check_state_ed);
        }
        stepBeans.add(stepBean);
        stepView.setStepBeanList(stepBeans);
    }

3)這裏使用了單位轉換的工具類

public class DensityUtil {

    /**
     * 根據手機的分辨率從 dp 的單位 轉成爲 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根據手機的分辨率從 px(像素) 的單位 轉成爲 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    /**
     * 獲取屏幕寬度
     *
     * @param context
     * @return
     */
    public static int getWidth(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        return wm.getDefaultDisplay().getWidth();
    }

    /**
     * 獲取屏幕高度
     *
     * @param context
     * @return
     */
    public static int getHeight(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        return wm.getDefaultDisplay().getHeight();
    }

    /**
     * 獲取圖片的寬高
     *
     * @param context
     * @param r
     * @return
     */
    public static int getImageWidth(Context context, int r) {
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), r);
        return bitmap.getWidth();
    }
}

至此一個簡單的自定義stepview就實現了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章