Android自定義控制元件之掃描動畫UI
前言
最近有一個需求,就是做一個掃描的UI,看了很多掃描動畫,發現酷狗的掃描動畫挺漂亮的,所以就做了一個相似的掃描動畫,廢話不多說,先看一下最終的效果吧。
最終效果圖
介紹
首先我們看一下這個效果,它由以下幾部分組成:
1.中間一個音符圖片
2.在音符圖片外面畫了三個圓環
3.一個旋轉的扇形動畫
既然知道它的結構那就來一步一步實現它吧。
準備
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewSize = 600 ;
setMeasuredDimension(viewSize, viewSize);
}
/**
* 從資源中解碼bitmap
*/
private void initBitmap() {
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.music_note);
}
在這裡為了方便直接把檢視的長寬設定為600,實際應用中可以自己去定製,但是長寬要一樣,然後就是在構造的時候解碼一下資原始檔中的音符圖片。然後就可以開始繪圖了。
繪圖
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint mPaint = new Paint();
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
Rect rectd = new Rect((viewSize / 10) * 4, (viewSize / 10) * 4, viewSize - (viewSize / 10) * 4, viewSize - (viewSize / 10 ) * 4);
canvas.drawBitmap(bitmap, rect, rectd, mPaint);
circlePaint = new Paint();
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeWidth((viewSize / 10));
circlePaint.setColor(Color.parseColor("#DDFA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 2.5f, circlePaint);
circlePaint.setColor(Color.parseColor("#AAFA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 3.5f, circlePaint);
circlePaint.setColor(Color.parseColor("#66FA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 4.5f, circlePaint);
sectorPaint = new Paint();
sectorPaint.setAntiAlias(true);
sectorPaint.setStyle(Paint.Style.STROKE);
sectorPaint.setStrokeWidth((viewSize / 10) * 3);
Shader sectorShader = new SweepGradient(viewSize / 2, viewSize / 2, new int[]{Color.TRANSPARENT, 0x00FA7298, 0xFFFA7298},
new float[]{0, 0.875f, 1f});
sectorPaint.setShader(sectorShader);
if (threadFlag) {
canvas.concat(matrix);
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 3.5f, sectorPaint);
}
}
這一段有點長,一個一個看,第一部分是畫圖片
Paint mPaint = new Paint();
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
Rect rectd = new Rect((viewSize / 10) * 4, (viewSize / 10) * 4, viewSize - (viewSize / 10) * 4, viewSize - (viewSize / 10) * 4);
canvas.drawBitmap(bitmap, rect, rectd, mPaint);
在這裡我們的目的是把整張圖畫進整張圖的最中心,這裡使用的是drawBitmap(Bitmap,Rect,Rect,Paint);這個方法。畫這張圖片需要建立兩個Rect,第一個Rect 代表要繪製的bitmap 區域,第二個 Rect 代表的是要將bitmap 繪製在螢幕的什麼地方。所以這裡第一個Rect我們 取值為整個Bitmap 區域 ,第二個Rect我們取值為view的五等分圓環由內向外第二圓環的外接正方形狀,說的這麼繞,大家仔細看下應該不難,也就是下圖中的藍色矩形。
circlePaint = new Paint();
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeWidth((viewSize / 10));
circlePaint.setColor(Color.parseColor("#DDFA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 2.5f, circlePaint);
circlePaint.setColor(Color.parseColor("#AAFA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 3.5f, circlePaint);
circlePaint.setColor(Color.parseColor("#66FA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 4.5f, circlePaint);
這一部分就是畫外面的三個圓環了,在這裡,我們給畫筆設定描邊不填充的屬性,然後再設定畫筆的寬度則可以實現圓環的繪製了,半徑的取值我相信大家稍微看下也能看懂。
sectorPaint = new Paint();
sectorPaint.setAntiAlias(true);
sectorPaint.setStyle(Paint.Style.STROKE);
sectorPaint.setStrokeWidth((viewSize / 10) * 3);
Shader sectorShader = new SweepGradient(viewSize / 2, viewSize / 2, new int[]{Color.TRANSPARENT, 0x00FA7298, 0xFFFA7298},
new float[]{0, 0.875f, 1f});
sectorPaint.setShader(sectorShader);
接下來的這部分用到了SweepGradient掃描梯度渲染,這裡簡單的介紹一下:
public SweepGradient(float cx, float cy, int colors[], float positions[])
public SweepGradient(float cx, float cy, int color0, int color1)
第一個方法 cx 、cy指圓型座標; colors[]、渲染顏色陣列,至少要兩個,positions[]設定相對位置的渲染,如果為null則均勻梯度渲染
第二個方法 cx 、cy指圓型座標;color0、 color1分別指起始渲染顏色和終止渲染顏色。
我們這裡使用的是第一種方法,從程式碼可以看出我們只渲染了1/8的扇形區域。
if (threadFlag) {
canvas.concat(matrix);
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 3.5f, sectorPaint);
}
這部分程式碼的功能就是隻有線上程開啟時才會繪製扇形渲染。同時根據在矩陣matrix中改變角度持續繪製達到扇形渲染掃描的效果。
動畫掃描執行緒
class ScanThread extends Thread {
private ScanView view;
public ScanThread(ScanView view) {
this.view = view;
}
@Override
public void run() {
super.run();
while (threadFlag) {
if (start) {
view.post(new Runnable() {
@Override
public void run() {
angle = angle + 5;
if (angle == 360) {
angle = 0;
}
matrix = new Matrix();
matrix.setRotate(angle, viewSize / 2, viewSize / 2);
view.invalidate();
}
});
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
這裡通過線上程中不斷對角度進行改變重繪才有了最終的效果
完整程式碼
public class ScanView extends View {
private static final String TAG = "ScanView";
/**
* 畫圓的筆
*/
private Paint circlePaint;
/**
* 畫扇形渲染的筆
*/
private Paint sectorPaint;
/**
* 掃描執行緒
*/
private ScanThread mThread;
/**
* 執行緒進行標誌
*/
private boolean threadFlag = false;
/**
* 執行緒啟動標誌
*/
private boolean start = false;
/**
* 扇形轉動的角度
*/
private int angle = 0;
/**
* 當前檢視的寬高,這裡相同
*/
private int viewSize;
/**
* 畫在view中間的圖片
*/
private Bitmap bitmap;
/**
* 對圖形進行處理的矩陣類
*/
private Matrix matrix;
public ScanView(Context context) {
this(context, null);
}
public ScanView(Context context, AttributeSet attrs) {
super(context, attrs);
initBitmap();
}
/**
* 此處設定viewSize固定值為600
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewSize = 600;
setMeasuredDimension(viewSize, viewSize);
}
/**
* 從資源中解碼bitmap
*/
private void initBitmap() {
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.music_note);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint mPaint = new Paint();
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
Rect rectd = new Rect((viewSize / 10) * 4, (viewSize / 10) * 4, viewSize - (viewSize / 10) * 4, viewSize - (viewSize / 10) * 4);
canvas.drawBitmap(bitmap, rect, rectd, mPaint);
circlePaint = new Paint();
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeWidth((viewSize / 10));
circlePaint.setColor(Color.parseColor("#DDFA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 2.5f, circlePaint);
circlePaint.setColor(Color.parseColor("#AAFA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 3.5f, circlePaint);
circlePaint.setColor(Color.parseColor("#66FA7298"));
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 4.5f, circlePaint);
sectorPaint = new Paint();
sectorPaint.setAntiAlias(true);
sectorPaint.setStyle(Paint.Style.STROKE);
sectorPaint.setStrokeWidth((viewSize / 10) * 3);
Shader sectorShader = new SweepGradient(viewSize / 2, viewSize / 2, new int[]{Color.TRANSPARENT, 0x00FA7298, 0xFFFA7298},
new float[]{0, 0.875f, 1f});
sectorPaint.setShader(sectorShader);
if (threadFlag) {
canvas.concat(matrix);
canvas.drawCircle(viewSize / 2, viewSize / 2, (viewSize / 10) * 3.5f, sectorPaint);
}
}
public void start() {
mThread = new ScanThread(this);
mThread.start();
threadFlag = true;
start = true;
}
public void stop() {
if (start) {
threadFlag = false;
start = false;
invalidate();
}
}
class ScanThread extends Thread {
private ScanView view;
public ScanThread(ScanView view) {
this.view = view;
}
@Override
public void run() {
super.run();
while (threadFlag) {
if (start) {
view.post(new Runnable() {
@Override
public void run() {
angle = angle + 5;
if (angle == 360) {
angle = 0;
}
matrix = new Matrix();
matrix.setRotate(angle, viewSize / 2, viewSize / 2);
view.invalidate();
}
});
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
終於實現了,再貼一下效果圖
完整的程式碼demo
結語
這是我寫的第一篇部落格,前前後後花了幾天晚上的時間,所幸今天終於出來了,雖然不難,但是也付出了努力,還是很激動的。希望以後有空能夠持續寫下去。
相關推薦
Android自定義控制元件之掃描動畫UI
前言 最近有一個需求,就是做一個掃描的UI,看了很多掃描動畫,發現酷狗的掃描動畫挺漂亮的,所以就做了一個相似的掃描動畫,廢話不多說,先看一下最終的效果吧。 最終效果圖 介紹 首先我們看一下這個效果,它由以下幾部分組成: 1.中間一個音符圖片
android自定義控制元件之圓形進度條(帶動畫)
首先貼上圖片: 額,感覺還行吧,就是進度條的顏色醜了點,不過咱是程式設計師,不是美工,配色這種問題當然不在考慮範圍之內了 下面說重點,如何來寫一個這樣的自定義控制元件。 首先,需要有一個灰色的底圖,來作為未填充時的進度條; 然後,根據傳入的當前進度值,繪製填充時的進度圓
Android自定義控制元件之區域性圖片放大鏡--BiggerView
零、前言: 本文的知識點一覽 1.自定義控制元件及自定義屬性的寫法,你也將對onMesure有更深的認識 2.關於bitmap的簡單處理,及canvas區域裁剪 3.本文會實現兩個自定義控制元件:FitImageView(圖片自適應)和BiggerView(放大鏡),前者為後者作為鋪墊。 4.最後會
Android自定義控制元件之仿汽車之家下拉重新整理
關於下拉重新整理的實現原理我在上篇文章Android自定義控制元件之仿美團下拉重新整理中已經詳細介紹過了,這篇文章主要介紹錶盤的動畫實現原理 汽車之家的下拉重新整理分為三個狀態: 第一個狀態為下拉重新整理狀態(pull to refresh),在這個狀
Android自定義控制元件之《折線圖的繪製》
金融軟體裡的行情分時圖,這是我們最常見的折線圖,當然了,折線圖的用途並不僅僅侷限於此,像一般在一定區間內,為了更好的能顯示出幅度的變化,那麼用折線圖來展示無疑是最符合效果的,當然了,網上也有很多的第
Android自定義控制元件之實現滑動選擇開關
前言:今天我們仿照著Google給我們提供的Switch控制元件來進行一次模仿,自己動手打造一個可以換滑動圖片以及背景的圖片。 -----------------分割線--------------- 先看一下google提供的Switc控制元件: 其實用法很簡單就當普通的
Android 自定義控制元件之繼承view
一.自定義控制元件的型別: 1.繼承view(自繪檢視:view中的內容是我們自己繪製出來的,需要重寫onDraw方法) 2.繼承已有原生控制元件 3.自定義組合控制元件(將系統原生的控制元件組合到一起) 本
Android自定義控制元件之百分比圓環進度條
首先我們先來看一下效果 分析 我們來看這個進度條應該分為3個小部分 1.中間的圓 2.外邊的圓環 3.中間的文字 分開畫 這3部分就是需要我們自己畫出來的,因此我們需要3根畫筆 //設定中心園的畫筆
Android自定義控制元件之圓形頭像
重寫ImageView public class CircleImageView extends ImageView { private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; p
Android 自定義控制元件之命運之輪(抽獎轉盤)
1 思路 首先肯定是要繪製扇形的,每一個獎品為一個扇形區分開,然後在扇形中得有當前獎品的說明,最後讓這個輪盤轉起來就行了。說起來很簡單,但是在繪製的時候,特別是繪製文字的時候還有有一些細節需要注意的,也不是難點,只是要理清楚那些地方應該怎麼去畫,怎麼獲取需要繪製的座標。
Android 自定義控制元件之ViewPager Indicator實現方式
介紹 ViewPager 的Indicator實現兩種效果 如下圖所示: 效果一 效果二 佈局檔案: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmln
Android自定義控制元件之測量onMeasure
由上圖可知,語法角度:子類可以重寫onMeasure,只能繼承View的measure,setMeasuredDimension方法。測量流程分為兩種情況討論:容器控制元件ViewGroup,原始的View(非容器控制元件)。原始的View測量,只需要測量自己的寬高;而容器控制元件需要先測量所有的子View
Android 自定義控制元件之 繼承佈局檔案
首先定義一個layout實現按鈕內部佈局: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andr
Android自定義控制元件之入門篇---整理網路上的資源
前言, 我的視訊系列 http://edu.csdn.net/course/detail/2741, 一起來學習Android… 本篇部落格主要是想要講解一下自定義控制元件如何入門,其中有好多資料資源來源自網路,綜合了網路上一些有些的博文
Android自定義控制元件之畫圓,並且修改其填充色
畫圓就是簡答呼叫了drawCircle的api public class Dot extends View { public Dot(Context context) { s
Android 自定義控制元件之打造流佈局實現熱門搜尋標籤
最終效果 首先來看看效果圖: 其他地方很好實現,就是熱門搜尋有點麻煩,由於資料的不確定性,那麼像GridView明顯不能滿足了,這時候就只能自己來定義一個佈局了。 最終實現後的效果: 具體實現 1,自定義一個類繼承
Android自定義控制元件之自定義TextView,實現drawableLeft可以和文字一起居中
LZ-Says:給大家推薦一個網站,有興趣可以查閱,想為大家貢獻一點自己的力量也可以投稿,老大稽核通過會發表,更好的幫助有需要的人~歡迎大家踴躍投稿~地址如下: http://ww
Android 自定義控制元件之基礎幾何圖形繪製詳解
前言 距離寫上一篇自定義View文章已經大半年過去了,一直想繼續寫,但是無奈技術有限,生怕誤人子弟。這段時間專案剛剛完成,有點時間,跟著大神的腳步,鞏固下自定義View的相關基礎知識。 Canvas&Paint Canvas和Pa
Android自定義控制元件之虛線的用法
Android實現畫虛線的方法 Android中可以通過DashPathEffect來實現,想知道關於PathEffect的詳細用法,請移步PathEffect的詳細用法 程式碼示例: PathE
Android 自定義控制元件之標籤控制元件
一、首先這是效果 二、實現原理 通過繼承ViewGroup,然後在重寫 onMeasure測量每個View的寬度,重新onLayout控制每個控制元件的位置, 並新增點選事件 三、實現 1、在onMeasure方法中得到顯示方式,並得到寬高 int widt