自定義View之儀表盤進度條
1. 前言
一點一點學習自定義View,按照《Android開發藝術探索》中的說法,自定義View大致可以分為4類:
1. 繼承View重寫onDraw方法;
2. 繼承ViewGroup派生特殊Layout;
3. 繼承特定View;
4. 繼承特定ViewGroup
看下第一種,製作一個簡單的儀表盤進度條。
2. 實現思路
- 繼承View;
- 自定義屬性值:arcColor,bgColor,arc_textColor,arc_textSize,分別是前景色,背景色,進度文字顏色,進度文字字型大小;
- 確定弧形繪製位置和文字繪製位置
- 實現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大致是相似的,可以根據以下代碼修改為與音頻相關的進