Android 自定義View篇(七)實現環形進度條效果

Android 自定義View篇(七)實現環形進度條效果

前言

Android 自定義 View 是高級進階不可或缺的內容,平常工做中,常常會遇到產品、UI 設計出花裏胡哨的界面。當系統自帶的控件不能知足開發需求時,就只能本身動手擼一個效果。
本文就帶自定義 View 初學者手動擼一個效果,經過自定義 View 實現圓形進度條功能,每行代碼都有註釋,保證易懂,看不懂你留言打我!!!android

實現效果

一、實現效果圖

Android 自定義View篇(七)實現環形進度條效果

二、源碼下載

https://github.com/jaynm888/CustomizeViewgit

三、步驟分析

實現以上效果,主要分爲四個步驟:github

  1. 自定義屬性
  2. 繪製圓環
  3. 繪製圓弧
  4. 更新進度條
  5. 繪製進度百分比

    代碼實現

一、自定義屬性

爲了實現絢麗多彩的環形進度條,將顏色、尺寸、風格等屬性抽離自定義屬性,這樣就能夠直接在 xml 文件中設置,根據項目徐需求能夠更方便使用。這裏將自定義屬性的步驟詳解說明一下:canvas

  1. 在 res/values 文件夾下新建 attrs.xml,將須要自定義的屬性申明定義:
<attr name="annulusColor" format="color"/>//圓環顏色
  <attr name="loadColor" format="color"/>//環形進度條加載顏色
  <attr name="annulusWidth" format="dimension"/>//圓環寬度
  <attr name="progress" format="integer"/>//圓環進度
  <attr name="textColor" format="color"/>//文本顏色
  <attr name="textSize" format="dimension"/>//文本字體大小
  <attr name="progressType">//環形進度條類型:0.實心 1.空心
      <enum name="fill" value="0"/>
      <enum name="stroke" value="1"/>
  </attr>
  <attr name="isShowText">//是否顯示文本:0.顯示 1.不顯示
      <enum name="yes" value="0"/>
      <enum name="no" value="1"/>
  </attr>

  <declare-styleable name="AnnulusCustomizeView">
      <attr name="annulusColor"/>
      <attr name="loadColor"/>
      <attr name="annulusWidth"/>
      <attr name="progress"/>
      <attr name="textColor"/>
      <attr name="textSize"/>
      <attr name="progressType"/>
      <attr name="isShowText"/>
  </declare-styleable>
  1. 在自定義 View 類中重寫帶有三個參數的構造方法,而後獲取自定義屬性:
// 獲取自定義屬性
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AnnulusCustomizeView, defStyleAttr, 0);
int indexCount = a.getIndexCount();
for (int i = 0; i < indexCount; i++) {
    int aIndex = a.getIndex(i);
    switch (aIndex) {
        case R.styleable.AnnulusCustomizeView_annulusWidth:
            mAnnulusWidth = a.getDimensionPixelSize(aIndex,
                    (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                            10,
                            getResources().getDisplayMetrics()));
            break;
        case R.styleable.AnnulusCustomizeView_annulusColor:
            mAnnulusColor = a.getColor(aIndex, Color.BLACK);
            break;
        case R.styleable.AnnulusCustomizeView_loadColor:
            mLoadColor = a.getColor(aIndex, Color.BLACK);
            break;
        case R.styleable.AnnulusCustomizeView_textColor:
            mTextColor = a.getColor(aIndex, Color.BLACK);
            break;
        case R.styleable.AnnulusCustomizeView_textSize:
            mTextSize = a.getDimensionPixelSize(aIndex,
                    (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                            15,
                            getResources().getDisplayMetrics()));
            break;
        case R.styleable.AnnulusCustomizeView_progressType:
            mProgressType = a.getInt(aIndex, 1);
            break;
        case R.styleable.AnnulusCustomizeView_isShowText:
            mIsShowText = a.getInt(aIndex, 1);
            break;
        case R.styleable.AnnulusCustomizeView_progress:
            mProgress = a.getInt(aIndex, 10);
            break;
    }
}
a.recycle();
  1. 在佈局頁面 xml 中應用自定義屬性,記得在父佈局添加命名空間:
    xmlns:app="http://schemas.android.com/apk/res-auto"app

    <com.caobo.customizeview.view.AnnulusCustomizeViewapp:layout_constraintStart_toStartOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:id="@+id/mAnnulusCustomizeView3"
    br/>android:layout_marginTop="100dp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:id="@+id/mAnnulusCustomizeView3"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:padding="20dp"
    app:isShowText="yes"
    app:annulusColor="#BB1"
    app:annulusWidth="15dp"
    app:loadColor="#CCC"
    app:progress="0"
    app:progressType="stroke"
    app:textColor="#000000"
    app:textSize="50dp" />ide

以上就完成了自定義屬性的聲明、獲取、應用的所有過程,android 中自帶的不少 View 源碼都有相關屬性,能夠本身查閱源碼學習,其實也很簡單。佈局

二、繪製圓環

圓環繪製 canvas.drawCircle()完成,定義圓環的 x、y 軸位置,半徑大小,設置畫筆相關屬性便可輕鬆完成。post

// TODO:繪製圓環
// 獲取圓形座標
int centre = getWidth() / 2;
// 獲取半徑
int radius = centre - mAnnulusWidth / 2;
// 取消鋸齒
mPaint.setAntiAlias(true);
// 設置畫筆寬度
mPaint.setStrokeWidth(mAnnulusWidth);
// 設置空心
mPaint.setStyle(Paint.Style.STROKE);
// 設置畫筆顏色
mPaint.setColor(mAnnulusColor);
canvas.drawCircle(centre, centre, radius, mPaint);

三、繪製圓弧

圓弧是進度條更新時,所掃過的範圍,圓弧繪製使用 canvas.drawArc()方法,具體繪製方法參數,這裏不作詳細描述,若是還不會的朋友,建議先補習一下 canvas 和 paint 相關 API 方法。學習

switch (mProgressType) {
  case STROKE:
      mPaint.setStyle(Paint.Style.STROKE);
      // 用於定義的圓弧的形狀和大小的界限
      RectF ovalStroke = new RectF(centre - radius, centre - radius, centre + radius, centre + radius);
      /**
       startAngle:從-90°開始,也就是鐘錶的12點鐘位置。
       sweepAngle:圓弧掃過的角度
       useCenter:設置咱們的圓弧在繪畫的時候,是否通過圓形,當Paint.Style.STROKE時,true無效果
       */
      canvas.drawArc(ovalStroke, -90, mProgress * 360 / maxProgress, false, mPaint);
      break;

  case FILL:
      mPaint.setStyle(Paint.Style.FILL);
      // 用於定義的圓弧的形狀和大小的界限
      RectF ovalFill = new RectF(centre - radius - mAnnulusWidth / 2, centre - radius - mAnnulusWidth / 2,
              centre + radius + mAnnulusWidth / 2, centre + radius + mAnnulusWidth / 2);
      canvas.drawArc(ovalFill, -90, mProgress * 360 / maxProgress, true, mPaint);
      break;
}

圓弧繪製根據相關自定義屬性,定義圓弧的形狀和大小的界限,很容易就能夠完成。字體

四、更新進度條

本文經過線程睡眠來模擬進度條更新,真實項目中會根據下載或者上傳進度來實時更新。
在自定義 View 中調用 postInvalidate()方法實時刷新繪製 View,實現進度條更新效果。

/**
 * 模擬數據
 */
private void setProgress() {
    new Thread() {
        @Override
        public void run() {
            for (int i = 1; i <= 100; i++) {
                mAnnulusCustomizeView1.setProgress(i);
                mAnnulusCustomizeView2.setProgress(i);
                mAnnulusCustomizeView3.setProgress(i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
}
/**
 * 根據外部進度傳遞更新View
 *
 * @param progress
 */
public synchronized void setProgress相關(final int progress) {
    this.mProgress = progress;
    new Thread() {
        @Override
        public void run() {
            if (mProgress == 100) {} // 完畢
            postInvalidate();
        }
    }.start();
}

五、繪製文本

進度條文本顯示在圓環中心,定義文本的 x、y 軸位置,文本大小和顏色,就可使用 canvas.drawText()方法完成繪製。

  1. 測量文本高度
    文本 0%——100%高度固定不變,因此可使用 Paint.getTextBounds()方法,提早測量出文本高度:
// 返回在邊界最小矩形,用戶測量文本高度,由於文本高度根據字體大小固定
mPaint.getTextBounds("%", 0, "%".length(), rect);
  1. 測量文本寬度
    使用 Paint.measureText()方法,根據實時更新進度百分比,獲取文本寬度
// 測量文本寬度
float measureTextWidth = mPaint.measureText(percentContext + "%");
  1. 定義文本 x、y 軸位置
    由於文本的 x、y 軸位置不在文本正中心,而在文本大概右下角位置,因此文本 x、y 軸位置測量方式須要你們注意:
int x = centre - measureTextWidth / 2;
int y = centre + rect.height() / 2;
  1. 文本繪製
    以上準備工做都就緒後,就能夠開始繪製文本了。
canvas.drawText(percentContext + "%", centre - measureTextWidth / 2, centre + rect.height() / 2, mPaint);

完成以上全部工做,就能夠實現一個絢麗的環形進度條功能了,是否是很簡單。

總結

自定 view 在 Android 開發過程當中應用極其普遍,爲了更好的掌握,建議從自定義 View 繪製流程、Canvas、Paint、Path、onLayout()、onMeasure()、onDraw()系統化學習,而後上手多作練習,這樣勢必會對自定義 View 有很好的提高!但願本文對初學自定義 View 的朋友有所幫助。
前文說過,保證每一個自定義 View 初學者都能看懂,由於每行代碼都會添加註釋,若是沒看懂的留言打我!!!
Android 自定義View篇(七)實現環形進度條效果
Android 自定義View篇(六)實現時鐘錶盤效果
Android 自定義View篇(七)實現環形進度條效果

相關文章
相關標籤/搜索