日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

【Android 应用开发】 自定义 圆形进度条 组件

發布時間:2025/6/17 Android 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android 应用开发】 自定义 圆形进度条 组件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載著名出處 :?http://blog.csdn.net/shulianghan/article/details/40351487


代碼下載 :?

-- CSDN 下載地址 :?http://download.csdn.net/detail/han1202012/8069497 ;

-- GitHub 地址 :?https://github.com/han1202012/CircleProcess.git ;

-- 工程示例 :?



一. 相關知識點解析



1. 自定義 View 組件構造方法


構造方法 : 自定義的 View 組件, 一般需要實現 三個構造方法, 分別有 一個, 兩個, 三個參數;

-- 一個參數 :?public CircleProcess(Context context);

-- 兩個參數 :?public CircleProcess(Context context, AttributeSet attrs);

-- 三個參數 :?public CircleProcess(Context context, AttributeSet attrs, int defStyle);


構造方法注意點 :?

-- 調用上級方法 : 每個構造方法中必須調用 super() 方法, 方法中的參數與該構造方法參數一樣;

-- 常用構造方法 : 一般在2參數構造方法中實現邏輯;


構造方法示例 :?

/** 畫筆 */private Paint mPaint;/** 上下文對象 */private Context mContext;/** 進度條的值 */private int mProcessValue;public CircleProcess(Context context, AttributeSet attrs) {super(context, attrs);// 初始化成員變量 ContextmContext = context;// 創建畫筆, 并設置畫筆屬性mPaint = new Paint();// 消除繪制時產生的鋸齒mPaint.setAntiAlias(true);// 繪制空心圓形需要設置該樣式mPaint.setStyle(Style.STROKE);}/*** 自定義布局實現的 只有 Context 參數的構造方法* @param context*/public CircleProcess(Context context) {super(context);}/*** 自定義布局實現的 三個參數的構造方法* @param context* @param attrs* @param defStyle*/public CircleProcess(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}

2. dip 和 px 單位轉換



(1) dip 轉 px


公式 :?

-- 基本公式 :?px / dip = dpi / 160;

-- 計算公式 : px = dpi / 160 * dip;


一些概念解析 :?

-- dpi 概念 : dpi (dot per inch), 每英寸像素數 歸一化的值 120 160 240 320 480;

-- 區分 dpi 和 density : dpi 是歸一化的值, density 是實際的值, 可能不是整數;


代碼示例 :?

/*** 將手機的 設備獨立像素 轉為 像素值* * 公式 : px / dip = dpi / 160* px = dip * dpi / 160;* @param context* 上下文對象* @param dpValue* 設備獨立像素值* @return* 轉化后的 像素值*/public static int dip2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}

(2) px 轉 dip


公式 :?

-- 基本公式 : px / dip = dpi / 160;

-- 計算公式 : dip = 160 / dpi * px;


代碼 :?

/*** 將手機的 像素值 轉為 設備獨立像素* 公式 : px/dip = dpi/160* dip = px * 160 / dpi* dpi (dot per inch) : 每英寸像素數 歸一化的值 120 160 240 320 480;* density : 每英寸的像素數, 精準的像素數, 可以用來計算準確的值* 從 DisplayMetics 中獲取的* @param context* 上下文對象* @param pxValue* 像素值* @return* 轉化后的 設備獨立像素值*/public static int px2dip(Context context, float pxValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}


3. 關于 組件 寬 和 高 計算



(1) MesureSpec 簡介


MeasureSpec 組成 : 每個?MeasureSpec 都代表一個 int 類型數值, 共 32 位, 前兩位是模式位, 后 30 位 是數值位;

-- 模式 : int 類型的前 2 位, 共有三種模式, 通過?MeasureSpec.getMode(int) 方法獲取, 下面會詳細介紹模式;

-- 大小 : int 類型的后 30 位, 通過?MeasureSpec.getSize(int) 方法獲取大小;


MeasureSpec 模式簡介 :?注意下面的數字是二進制的

-- 00 : MeasureSpec.UNSPECIFIED, 未指定模式;
-- 01 : MeasureSpec.EXACTLY, 精準模式;
-- 11 : MeasureSpec.AT_MOST, 最大模式;


MeasureSpec 常用方法介紹 :?

-- MeasureSpec.getMode(int) : 獲取模式;
-- MeasureSpec.getSize(int) : 獲取大小;
-- MeasureSpec.makeMeasureSpec(int size, int mode) : 創建一個 MeasureSpec;
-- MeasureSpec.toString(int) : 模式 + 大小 字符串;



(2) 通過 MeasureSpec?計算組件大小


計算方法 :?

-- 精準模式 : 該模式下 長度的大小 就是 從?MeasureSpec 中獲取的 size 大小;

-- 最大模式 : 獲取 默認大小 和 size 中的較小的那個;

-- 未定義模式 : 默認大小;


通用計算方法代碼 :?

/*** 獲取組件寬度* * MeasureSpec : 該 int 類型有 32 位, 前兩位是狀態位, 后面 30 位是大小值;* 常用方法 : * -- MeasureSpec.getMode(int) : 獲取模式* -- MeasureSpec.getSize(int) : 獲取大小* -- MeasureSpec.makeMeasureSpec(int size, int mode) : 創建一個 MeasureSpec;* -- MeasureSpec.toString(int) : 模式 + 大小 字符串* * 模式介紹 : 注意下面的數字是二進制的* -- 00 : MeasureSpec.UNSPECIFIED, 未指定模式;* -- 01 : MeasureSpec.EXACTLY, 精準模式;* -- 11 : MeasureSpec.AT_MOST, 最大模式;* * 注意 : 這個 MeasureSpec 模式是在 onMeasure 方法中自動生成的, 一般不用去創建這個對象* * @param widthMeasureSpec* MeasureSpec 數值* @return* 組件的寬度*/private int measure(int measureSpec) {//返回的結果, 即組件寬度int result = 0;//獲取組件的寬度模式int mode = MeasureSpec.getMode(measureSpec);//獲取組件的寬度大小 單位pxint size = MeasureSpec.getSize(measureSpec);if(mode == MeasureSpec.EXACTLY){//精準模式result = size;}else{//未定義模式 或者 最大模式//注意 200 是默認大小, 在 warp_content 時使用這個值, 如果組件中定義了大小, 就不使用該值result = dip2px(mContext, 200);if(mode == MeasureSpec.AT_MOST){//最大模式//最大模式下獲取一個稍小的值result = Math.min(result, size);}}return result;}

(3) 設置 組件大小方法


setMeasuredDimension() 方法 : 該方法決定 View 組件的大小;

-- 使用場所 : 在 onMeasure() 方法中調用該方法, 就設置了組件的寬 和 高, 然后在其它位置調用 getWidth() 和 getHeight() 方法時, 獲取的就是 該方法設置的值;

-- 代碼示例 :?

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);/** setMeasuredDimension 方法 : 該方法決定當前的 View 的大小* 根據 View 在布局中的顯示, 動態獲取 View 的寬高* * 當布局組件 warp_content 時 : * 從 MeasureSpec 獲取的寬度 : 492 高度 836 , * 默認 寬高 都是 120dip轉化完畢后 180px * * 當將布局組件 的寬高設置為 240 dp : * 寬度 和 高度 MeasureSpec 獲取的都是 360, 此時 MeasureSpec 屬于精準模式* */setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec));}

4. 圖形繪制


(1) 設置畫筆


畫筆相關方法 :?

-- 消除鋸齒 :?setAntiAlias(boolean);

// 消除繪制時產生的鋸齒mPaint.setAntiAlias(true);

-- 繪制空心圓設置的樣式 :?setStyle(Style.STROKE);

// 繪制空心圓形需要設置該樣式mPaint.setStyle(Style.STROKE);

-- 繪制實心圖形文字需要設置的樣式 :?mPaint.setStrokeWidth(0);

-- 設置畫筆顏色 :?setColor(Color.BLUE);

-- 設置文字大小 :?setTextSize(float);

//設置數字的大小, 注意要根據 內圓半徑設置mPaint.setTextSize(innerRadius / 2);

(2) 繪制圖形


繪制圓 :?canvas.drawCircle(float cx, float cy, float radius, Paint paint);

-- cx 參數 : 圓心的 x 軸距離;

-- cy 參數 : 圓心的 y 軸距離;

-- radius 參數 : 半徑;

-- paint : 畫筆;


繪制圓弧 :?

-- 創建圓弧 :?RectF rectf = new RectF(left, top, right, bottom);

-- 繪制 :?canvas.drawArc(rectf, 270, mProcessValue, false, mPaint);

-- 示例 :?

//創建圓弧對象RectF rectf = new RectF(left, top, right, bottom);//繪制圓弧 參數介紹 : 圓弧, 開始度數, 累加度數, 是否閉合圓弧, 畫筆canvas.drawArc(rectf, 270, mProcessValue, false, mPaint);
繪制文字 :?canvas.drawText(str, textX, textY, mPaint);



二. 代碼示例


1. 自定義 View 代碼


package cn.org.octopus.circle;import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.util.AttributeSet; import android.widget.ImageView;public class CircleProcess extends ImageView {/** 畫筆 */private Paint mPaint;/** 上下文對象 */private Context mContext;/** 進度條的值 */private int mProcessValue;public CircleProcess(Context context, AttributeSet attrs) {super(context, attrs);// 初始化成員變量 ContextmContext = context;// 創建畫筆, 并設置畫筆屬性mPaint = new Paint();// 消除繪制時產生的鋸齒mPaint.setAntiAlias(true);// 繪制空心圓形需要設置該樣式mPaint.setStyle(Style.STROKE);}/*** 自定義布局實現的 只有 Context 參數的構造方法* @param context*/public CircleProcess(Context context) {super(context);}/*** 自定義布局實現的 三個參數的構造方法* @param context* @param attrs* @param defStyle*/public CircleProcess(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//獲取圓心的 x 軸位置int center = getWidth() / 2;/** 中間位置 x 減去左側位置 的絕對值就是圓半徑, * 注意 : 由于 padding 屬性存在, |left - right| 可能與 width 不同*/int outerRadius = Math.abs(getLeft() - center);//計算內圓半徑大小, 內圓半徑 是 外圓半徑的一般int innerRadius = outerRadius / 2;//設置畫筆顏色mPaint.setColor(Color.BLUE);//設置畫筆寬度mPaint.setStrokeWidth(2);//繪制內圓方法 前兩個參數是 x, y 軸坐標, 第三個是內圓半徑, 第四個參數是 畫筆canvas.drawCircle(center, center, innerRadius, mPaint);/** 繪制進度條的圓弧* * 繪制圖形需要 left top right bottom 坐標, 下面需要計算這個坐標*///計算圓弧寬度int width = outerRadius - innerRadius;//將圓弧的寬度設置給 畫筆mPaint.setStrokeWidth(width);/** 計算畫布繪制圓弧填入的 top left bottom right 值, * 這里注意給的值要在圓弧的一半位置, 繪制的時候參數是從中間開始繪制*/int top = center - (innerRadius + width/2);int left = top;int bottom = center + (innerRadius + width/2);int right = bottom;//創建圓弧對象RectF rectf = new RectF(left, top, right, bottom);//繪制圓弧 參數介紹 : 圓弧, 開始度數, 累加度數, 是否閉合圓弧, 畫筆canvas.drawArc(rectf, 270, mProcessValue, false, mPaint);//繪制外圓mPaint.setStrokeWidth(2);canvas.drawCircle(center, center, innerRadius + width, mPaint);/** 在內部正中央繪制一個數字*///生成百分比數字String str = (int)(mProcessValue * 1.0 / 360 * 100) + "%"; /** 測量這個數字的寬 和 高*///創建數字的邊界對象Rect textRect = new Rect();//設置數字的大小, 注意要根據 內圓半徑設置mPaint.setTextSize(innerRadius / 2);mPaint.setStrokeWidth(0);//獲取數字邊界mPaint.getTextBounds(str, 0, str.length(), textRect);int textWidth = textRect.width();int textHeight = textRect.height();//根據數字大小獲取繪制位置, 以便數字能夠在正中央繪制出來int textX = center - textWidth / 2;int textY = center + textHeight / 2;//正式開始繪制數字canvas.drawText(str, textX, textY, mPaint);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);/** setMeasuredDimension 方法 : 該方法決定當前的 View 的大小* 根據 View 在布局中的顯示, 動態獲取 View 的寬高* * 當布局組件 warp_content 時 : * 從 MeasureSpec 獲取的寬度 : 492 高度 836 , * 默認 寬高 都是 120dip轉化完畢后 180px * * 當將布局組件 的寬高設置為 240 dp : * 寬度 和 高度 MeasureSpec 獲取的都是 360, 此時 MeasureSpec 屬于精準模式* */setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec));}/*** 獲取組件寬度* * MeasureSpec : 該 int 類型有 32 位, 前兩位是狀態位, 后面 30 位是大小值;* 常用方法 : * -- MeasureSpec.getMode(int) : 獲取模式* -- MeasureSpec.getSize(int) : 獲取大小* -- MeasureSpec.makeMeasureSpec(int size, int mode) : 創建一個 MeasureSpec;* -- MeasureSpec.toString(int) : 模式 + 大小 字符串* * 模式介紹 : 注意下面的數字是二進制的* -- 00 : MeasureSpec.UNSPECIFIED, 未指定模式;* -- 01 : MeasureSpec.EXACTLY, 精準模式;* -- 11 : MeasureSpec.AT_MOST, 最大模式;* * 注意 : 這個 MeasureSpec 模式是在 onMeasure 方法中自動生成的, 一般不用去創建這個對象* * @param widthMeasureSpec* MeasureSpec 數值* @return* 組件的寬度*/private int measure(int measureSpec) {//返回的結果, 即組件寬度int result = 0;//獲取組件的寬度模式int mode = MeasureSpec.getMode(measureSpec);//獲取組件的寬度大小 單位pxint size = MeasureSpec.getSize(measureSpec);if(mode == MeasureSpec.EXACTLY){//精準模式result = size;}else{//未定義模式 或者 最大模式//注意 200 是默認大小, 在 warp_content 時使用這個值, 如果組件中定義了大小, 就不使用該值result = dip2px(mContext, 200);if(mode == MeasureSpec.AT_MOST){//最大模式//最大模式下獲取一個稍小的值result = Math.min(result, size);}}return result;}/*** 將手機的 設備獨立像素 轉為 像素值* * 公式 : px / dip = dpi / 160* px = dip * dpi / 160;* @param context* 上下文對象* @param dpValue* 設備獨立像素值* @return* 轉化后的 像素值*/public static int dip2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}/*** 將手機的 像素值 轉為 設備獨立像素* 公式 : px/dip = dpi/160* dip = px * 160 / dpi* dpi (dot per inch) : 每英寸像素數 歸一化的值 120 160 240 320 480;* density : 每英寸的像素數, 精準的像素數, 可以用來計算準確的值* 從 DisplayMetics 中獲取的* @param context* 上下文對象* @param pxValue* 像素值* @return* 轉化后的 設備獨立像素值*/public static int px2dip(Context context, float pxValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}/*** 獲取當前進度值* @return* 返回當前進度值*/public int getmProcessValue() {return mProcessValue;}/*** 為該組件設置進度值* @param mProcessValue* 設置的進度值參數*/public void setmProcessValue(int mProcessValue) {this.mProcessValue = mProcessValue;}}

2. Activity 代碼


package cn.org.octopus.circle;import android.app.Activity; import android.app.ActionBar; import android.app.Fragment; import android.os.AsyncTask; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.os.Build;public class MainActivity extends Activity {private static CircleProcess circle_process;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//加載 Fragmentif (savedInstanceState == null) {getFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();}new CircleProcessAnimation().execute();}/*** 設置 異步任務, 在這個任務中 設置 圓形進度條的進度值* @author octopus **/class CircleProcessAnimation extends AsyncTask<Void, Integer, Void>{@Overrideprotected Void doInBackground(Void... arg0) {for(int i = 1; i <= 360; i ++){try {//激活圓形進度條顯示方法publishProgress(i);//每隔 50 毫秒更新一次數據Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}return null;}@Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);//為圓形進度條組件設置進度值circle_process.setmProcessValue(values[0]);//刷新圓形進度條顯示circle_process.invalidate();}}/*** 界面顯示的 Fragment * @author octopus*/public static class PlaceholderFragment extends Fragment {public PlaceholderFragment() {}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View rootView = inflater.inflate(R.layout.fragment_main, container, false);circle_process = (CircleProcess) rootView.findViewById(R.id.circle_process);return rootView;}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {int id = item.getItemId();if (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);} }

3. 布局文件代碼?


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="cn.org.octopus.circle.MainActivity$PlaceholderFragment"android:gravity="center"><cn.org.octopus.circle.CircleProcess android:id="@+id/circle_process"android:layout_width="300dip"android:layout_height="300dip"/></RelativeLayout>


代碼下載?:?

--?CSDN 下載地址?:?http://download.csdn.net/detail/han1202012/8069497?;

--?GitHub 地址?:?https://github.com/han1202012/CircleProcess.git?;

--?工程示例?:?




總結

以上是生活随笔為你收集整理的【Android 应用开发】 自定义 圆形进度条 组件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。