1. 程式人生 > >自定義View之儀表盤進度條

自定義View之儀表盤進度條

1. 前言

一點一點學習自定義View,按照《Android開發藝術探索》中的說法,自定義View大致可以分為4類:
1. 繼承View重寫onDraw方法;
2. 繼承ViewGroup派生特殊Layout;
3. 繼承特定View;
4. 繼承特定ViewGroup

看下第一種,製作一個簡單的儀表盤進度條。

2. 實現思路

  1. 繼承View;
  2. 自定義屬性值:arcColor,bgColor,arc_textColor,arc_textSize,分別是前景色,背景色,進度文字顏色,進度文字字型大小;
  3. 確定弧形繪製位置和文字繪製位置
  4. 實現onDraw()方法

3. 效果

這裡寫圖片描述

4. 知識點

4.1 MeasureSpec

MeasureSpec代表一個32位int值,高2位代表SpecMode,低30位代表SpecSize。SpecMode指的是測量模式,SpecSize指的是對應測量模式下的大小。

SpecMode有下面如下3中模式:

        /**
         * Measure specification mode: The parent has not imposed any constraint
         * on the child. It can be whatever size it wants.
         */
public static final int UNSPECIFIED = 0 << MODE_SHIFT; /** * Measure specification mode: The parent has determined an exact size * for the child. The child is going to be given those bounds regardless * of how big it wants to be. */ public
static final int EXACTLY = 1 << MODE_SHIFT; /** * Measure specification mode: The child can be as large as it wants up * to the specified size. */ public static final int AT_MOST = 2 << MODE_SHIFT;
SpecMode 描述
UNSPECIFIED 父容器不對View有任何限制,系統涉及,平時很少涉及
EXACTLY 父容器已經檢測出View所需要的精準大小,即SpecSize的大小。對應match_parent和固定數值兩種情況
AT_MOST 父容器指定一個View可用的大小。View的大小不能超過這個值,具體是什麼值要看View的具體實現。對應wrap_content情況

SpecSize大小單位px。

生成MeasureSpec方式如下:

public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
                                          @MeasureSpecMode int mode) {
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode & MODE_MASK);
            }
        }

獲取size和mode的方式

        /**
         * Extracts the mode from the supplied measure specification.
         *
         * @param measureSpec the measure specification to extract the mode from
         * @return {@link android.view.View.MeasureSpec#UNSPECIFIED},
         *         {@link android.view.View.MeasureSpec#AT_MOST} or
         *         {@link android.view.View.MeasureSpec#EXACTLY}
         */
        @MeasureSpecMode
        public static int getMode(int measureSpec) {
            //noinspection ResourceType
            return (measureSpec & MODE_MASK);
        }

        /**
         * Extracts the size from the supplied measure specification.
         *
         * @param measureSpec the measure specification to extract the size from
         * @return the size in pixels defined in the supplied measure specification
         */
        public static int getSize(int measureSpec) {
            return (measureSpec & ~MODE_MASK);
        }

4.2 View的工作流程

過程 描述
onMeasure 測量過程,確定View的寬度和高度,傳入的引數是widthMeasureSpec,heightMeasureSpec
onLayout 佈局過程,確定View的上下左右四個角的位置
onDraw 繪製過程,一般用來繪製特殊圖形

繼承View的自定義View基本只需要關注onDraw()和onMeasure()。由於沒有子View所以不需要關注onLayout()。

4.3 圖形繪製

具體請檢視Canvas類和Paint類,這兩個類內容比較多,可以自己研究一下,有很多有用的東西。

4.3.1 Canvas繪製方法

這裡寫圖片描述

4.3.2 Paint屬性值

Paint列舉值
這裡寫圖片描述

設定屬性方法
這裡寫圖片描述

5. 關鍵程式碼

5.1 attrs.xml

    <declare-styleable name="ArcView">
        <attr name="arcColor" format="color"/>
        <attr name="bgColor" format="color"/>
        <attr name="arc_textColor" format="color"/>
        <attr name="arc_textSize" format="dimension"/>
    </declare-styleable>

5.2 ArcView

public class ArcView extends View {

    private final int MAX_SWEEP_ANGLE = 240;
    private final int START_SWEEP_ANGLE = 150;
    private final int DEFAULT_MAX_PROGRESS = 100;

    private final int DEFAULT_ARC_COLOR = Color.RED;
    private final int DEFAULT_BG_COLOR = Color.DKGRAY;
    private final int DEFAULT_TEXT_COLOR = Color.BLACK;
    private final int DEFAULT_TEXT_SIZE = 40;

    private int mArcColor = DEFAULT_ARC_COLOR;
    private int mBgColor = DEFAULT_BG_COLOR;
    private int mTextColor = DEFAULT_TEXT_COLOR;
    private int mTextSize = DEFAULT_TEXT_SIZE;

    private int progress = 0;
    private int mMaxProgress = DEFAULT_MAX_PROGRESS;

    private Paint mCirclePaint;
    private Paint mBgPaint;
    private Paint mTextPaint;

    private final Rect mTextBound = new Rect();

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

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

    public ArcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        final TypedArray attributes = getContext().obtainStyledAttributes(attrs,
                R.styleable.ArcView);

        mArcColor = attributes
                .getColor(
                        R.styleable.ArcView_arcColor,
                        DEFAULT_ARC_COLOR);

        mBgColor = attributes
                .getColor(
                        R.styleable.ArcView_bgColor,
                        DEFAULT_BG_COLOR);

        mTextColor = attributes
                .getColor(
                        R.styleable.ArcView_arc_textColor,
                        DEFAULT_TEXT_COLOR);

        mTextSize = (int) attributes
                .getDimension(
                        R.styleable.ArcView_arc_textSize,
                        DEFAULT_TEXT_SIZE);
        attributes.recycle();
        init();
    }

    private void init() {
        mCirclePaint = new Paint();
        mCirclePaint.setColor(mArcColor);
        mCirclePaint.setStrokeWidth(8.0F);
        mCirclePaint.setDither(true);
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setStyle(Paint.Style.STROKE);


        mBgPaint = new Paint();
        mBgPaint.setColor(mBgColor);
        mBgPaint.setStrokeWidth(20.0F);
        mBgPaint.setAntiAlias(true);
        mBgPaint.setStyle(Paint.Style.STROKE);
        mBgPaint.setStrokeCap(Paint.Cap.ROUND);

        mTextPaint = new Paint();
        mTextPaint.setStrokeWidth(4);

        //字型SP單位轉換成PX
        int size =  (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                mTextSize, getResources().getDisplayMetrics());
        mTextPaint.setTextSize(size);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextAlign(Paint.Align.LEFT);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();

        int circleWidth = getWidth() - paddingLeft - paddingRight;
        int circleHeight = getHeight() - paddingTop - paddingBottom;

        int radius = Math.min(circleWidth, circleHeight) / 2;

        int left = getLeft() + paddingLeft;
        int right = left + radius * 2;
        int top = getTop() + getPaddingTop();
        int bottom = top + 2 * radius;
        canvas.drawArc(left, top, right, bottom, START_SWEEP_ANGLE, MAX_SWEEP_ANGLE, false,
                mBgPaint);

        int sweepArc = MAX_SWEEP_ANGLE * progress / mMaxProgress;
        canvas.drawArc(left, top, right, bottom, START_SWEEP_ANGLE, sweepArc, false, mCirclePaint);

        String text = String.valueOf(progress) + "%";
        mTextPaint.getTextBounds(text, 0, text.length(),
                mTextBound);
        canvas.drawText(text, (left + right) / 2 - mTextBound.width() / 2,
                (top + bottom) / 2 + mTextBound.height() / 2, mTextPaint);
    }

    /**
     * 設定進度大小
     */
    public void setProgress(int progress) {
        if (progress < 0 || progress > mMaxProgress) {
            return;
        }
        this.progress = progress;
        invalidate();
    }

    /**
     * 設定最大進度值
     */
    public void setMaxProgress(int maxProgress) {
        this.mMaxProgress = maxProgress;
    }
}

6. 原始碼

原始碼已上傳Github,後續自定義View的學習Demo也會陸續上傳

最後

關注「碼道長」,瞭解最前沿的技術知識,擡高自己的天花板。
這裡寫圖片描述

相關推薦

定義View儀表盤進度

1. 前言 一點一點學習自定義View,按照《Android開發藝術探索》中的說法,自定義View大致可以分為4類: 1. 繼承View重寫onDraw方法; 2. 繼承ViewGroup派生特殊Layout; 3. 繼承特定View; 4. 繼承特定

Android繪圖:定義View——矩形進度、圓環進度、填充型進度、時鐘

主函式 這幾種進度條的主函式都是類似的,所以下面我只給出了一個填充型進度條的主函式,其他幾個主函式只是在這基礎上改動一下按鈕id(即與各自佈局裡面的id相同即可),還有改動一下相對應的類即可。 public class MainActivity

使用定義View繪製圓形進度效果

首先自定義屬性 res - values - attrs(自己建立): <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyCicle">

定義View實現圓形進度跳轉頁面

效果: //首先在values資料夾下建立一個attrs.xml: ?xml version=“1.0” encoding=“utf-8”?> //佈局: <?xml version="1.0" encoding="utf-8"?>

Android定義view-繪製圓形進度

詳細可參考:http://blog.csdn.net/Beyond0525/article/details/48181345最近專案上有一些需求,需要繪製圓形的進度條滿足設計上和互動上的需求: 實現思路在畫布上直接繪製View,需要了解一下幾點 1.需要畫一個圓 2.圓圈上有

android_studio的定義View的圓形進度

**需要 考試第三方** **MyView寫法如下** package com.bawei.lss_yuan; import android.content.Context; import android.content.res.TypedArray; imp

定義View:重繪進度

最近下大工夫功課自定義View這一關。我把自定義View劃分為八個類別,寫完這八個類別,我就基本上弄清楚自定義控制元件的門道了。以下是我自己劃分的八個類別: 1.使用現有控制元件佈局,對子控制元件進行格式化和監聽,純程式碼實現; 2.使用現有控制元件佈局,對子控制元件進行格

Android定義View畫圓+進度+定義View梯形

//自定義進度圓圈 package com.bw.20171104; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas

定義View進度百分比ProgressBar

先上幾張自定義所實現的效果圖吧,有興趣的可以繼續往下看        實現思路,前四張圖呢在自定義progressbar時沒有加入text文字,文字是在xml佈局時加上去的,最後一張是與progressbar定義在一起的。可以看到有以下幾種情況 1,圖1自定義中未整合

Android 定義View實現圓形進度 深入理解onDraw和onMeasure及定義屬性

Android的View類是使用者介面的基礎構件,表示螢幕上的一塊矩形區域,負責這個區域的繪製和事件處理。自定義View的過程主要包括重寫onDraw及onMeasure方法 , 其中onMeasure方法的作用就是計算出自定義View的寬度和高度。這個計算的過

Android 定義View 圓形百分比進度

Android 自定義View  圓形百分比進度條 自定義View package com.arch.circleprogressview; import android.content.Context; import android.graphics.Canvas;

android 定義View載入圓形進度

實現效果如下: 主要步驟如下幾步: 1.記載自定義屬性的值: public CircleProgressBar(Context context, @Nullable AttributeS

定義View簡單定義圓形進度

達到的效果如下: 從上面的效果可以看出,主要有以下幾個自定義屬性: 1、背景顏色 2、進度扇形顏色 3、半徑 4、起始角度 因此,在attrs.xml中定義如下屬性: <?xml version="1.0" encoding="utf-8

定義View漸變色圓形進度

先展示下效果圖: 然後按照自定義view的步驟來實現。 我們需要將目標定義清楚: 目標是漸變色圓形進度條,那麼,使用canvas畫弧形是基礎了,另外是漸變色的效果,這裡使用LinearGradient來實現。 既然是提供一個進度條,那麼,是需要自定義

Android 定義View仿華為圓形載入進度

效果圖 實現思路 可以看出該View可分為三個部分來實現 最外圍的圓,該部分需要區分進度圓和底部的刻度圓,進度部分的刻度需要和底色刻度區分開來 中間顯示的文字進度,需要讓文字在View中居中顯示 旋轉的小圓點,小圓點需要模擬小球下落運動時的加速度

Android 定義view圓盤進度

很久沒有用到自定義View了,手有點生疏了,這不同事剛扔給一個活,按照UI的要求,畫一個進度條,帶動畫效果的。需求是這樣的: 嗯,實現後效果如下: 嗯,算是基本滿足需求吧。 本文包含的知識點 1、自定義view的繪製 2、屬性動畫 3、影象的

Android定義View實現簡單炫酷的球體進度

前言 最近一直在研究自定義view,正好專案中有一個根據下載進度來實現球體進度的需求,所以自己寫了個進度球,程式碼非常簡單。先看下效果: 效果還是非常不錯的。 準備知識 要實現上面的效果我們只要掌握兩個知識點就好了,一個是Handler機制,用於發訊息重新整理我們的進度球,一個是clip

Android定義View水波紋顯示進度效果

@Override protected void onDraw(Canvas canvas) { if (null != backgroundBitmap) { canvas.drawBitmap(createImage(), 0, 0, null);

Android定義View仿京東售後稽核進度

本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出 概述:同常在做商城類的App時,都會有售後的需求,而售後流程通常會因為不同的業務,而分為不確定的幾個步驟,如下圖所示: 那麼問題就來了,像這樣的效果如何實現呢?讓我們先放下這個問題,先看

小程序開發如何實現視頻或音頻定義可拖拽進度

text 完成 我們 控制 轉載 產品 結構 可拖拽 step 程序原生組件的音頻播放時並沒有進度條的顯示,而此次在我們所接的項目中,鑒於原生的視頻進度條樣式太醜,產品要求做一個可拖拽的進度條滿足需求。視頻和音頻提供的api大致是相似的,可以根據以下代碼修改為與音頻相關的進