自定義View詳解(3)
大家教師節快樂啊,不知道勤學的Coder們有沒有去嘗試下繪製上篇文章中最後留下的進階效果,不管怎樣,還是一起動手寫一遍吧!看看套路是否一致。
水波紋
首先來看圖-水波紋中的效果,其具有以下特點:
-
從內到外四層,內圓外環;
-
從內到外四個色值;
-
最內部圓局於View中心;
-
圓和環同心;
看出以下幾點,我們就可以開始按照套路畫圖了,老套路走起(在以後自定義View部分新建專案及類相關的描述不再贅述)。
宣告畫筆和寬高
1.宣告畫筆及寬高 如上分析,我們需要兩個畫筆,一個用於繪製內圓,一個用於繪製外環。
/** * 繪製最中心圓的Paint */ private Paint mInnerCirclePaint; /** * 繪製外部圓環的Paint */ private Paint mOutterRingPaint; /** * View寬度 */ private int mWidth; /** * View高度 */ private int mHeight; /** * 外環寬度 */ private int mOuttterRingWidth = 50;
2.初始化畫筆並在建構函式內呼叫 由於外部為圓環,所以外部畫筆樣式設定為空心,內部圓畫筆樣式設定為實心,同時設定畫筆寬度為外部圓環寬度。
public WaveView(Context context) { super(context); init(); } public WaveView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mInnerCirclePaint.setColor(Color.BLUE); /** 內部畫筆為實心 **/ mInnerCirclePaint.setStyle(Style.FILL); mOutterRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mOutterRingPaint.setColor(Color.BLUE); /** 外部畫筆為空心 **/ mOutterRingPaint.setStyle(Style.STROKE); mOutterRingPaint.setStrokeWidth(mOuttterRingWidth); }
3.初始化寬高
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w > 0 && h > 0){
mWidth = w;
mHeight = h;
}
}
計算Points
宣告內圓半徑,圓環寬度,計算各圓的半徑,同心圓及圓環,圓心位於View中心。
如圖-水波紋內部距離說明,外環所在圓依次為(radius為外環半徑,mInnerRadius為內圓半徑,mOutterRingWidth為環寬度):
一環:半徑與內圓半徑一致,radius = mInnerRadius+(mOutterRingWidth/2)1; 二環:半徑等於內圓半徑+圓環寬度,radius = mInnerRadius + (mOutterRingWidth/2)3; … 依次類推,我們可以得到外部圓環半徑公式:
radius = mInnerRadius + (mOutterRingWidth/2) * i;(i取1,3,5,7,9…)
如此我們就可以開始擼碼了。
/* 宣告必要變數 */
/**
* 內圓半徑
*/
private int mInnerRadius = 50;
/**
* 儲存計算所得的外環半徑
*/
private int[] mRadius = new int[4];
/* 計算外環半徑 */
private void calculateRadius() {
for (int i = 0; i < 4; i++) {
mRadius[i] = mInnerRadius + (i * 2 + 1) * mOuttterRingWidth / 2;
}
}
獲取畫布繪製圓及圓環
重寫onDraw函式獲取canvas,並繪製圓環及內圓。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
calculateRadius();
canvas.drawCircle(mWidth / 2, mHeight / 2, mInnerRadius, mInnerCirclePaint);
for (int i = 0; i < 4; i++) {
/** 改變外環的顏色透明度 **/
mOutterRingPaint.setAlpha(255 - (int) (255 * ((float) (i + 1) / 5)));
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius[i], mOutterRingPaint);
}
}
至於執行效果,大家自己動手試一下嘍!
動起來的水波紋
雖然我們畫出來了水波紋,但是和藹的產品還是會批鬥你的,他會說,你家水波紋靜態的哦?這一秒鐘心裡是不是有一萬隻羊駝奔騰?哈哈!奔騰歸奔騰,需求我們還是要實現下滴。
那麼我們來觀察下現實中的水波紋,不難發現與圖-水波紋形成 相似的過程。
我們可以看出水波紋動態形成的本質是,外部圓環逐步擴張增加形成的。那麼我們只需要動態控制外部圓環的繪製個數,就可以讓它動起來了。
屬性動畫
說到控制外環個數動態增長,做過動畫的朋友第一個直覺肯定就是屬性動畫嘍,這樣是值變化,所以我們使用ValueAnimator
即可(關於屬性動畫,幀動畫,View動畫相關的細節,我們在後續文章中單獨說明)。
1.宣告動畫相關的成員
/**
* 控制外環個數變化的屬性動畫物件
*/
private ValueAnimator mValueAnimator;
/**
* 繪製的外環總個數
*/
private int mOutterRingCount = 4;
2.初始化動畫物件並開始
public void startAnimation(){
//建立ValueAnimator物件,按照整型值從0變化到4
mValueAnimator = ValueAnimator.ofInt(0,5);
//設定動畫重複型別,RESTART--重新開始,REVERSE--值反轉
mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
//設定動畫重複次數,-1--不限制次數
mValueAnimator.setRepeatCount(-1);
mValueAnimator.setDuration(2000);
mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mOutterRingCount = (int) valueAnimator.getAnimatedValue();
postInvalidate();
}
});
mValueAnimator.start();
}
3.更新onDraw
迴圈引數
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
calculateRadius();
canvas.drawCircle(mWidth / 2, mHeight / 2, mInnerRadius, mInnerCirclePaint);
for (int i = 0; i < mOutterRingCount; i++) {
mOutterRingPaint.setAlpha(255 - (int) (255 * ((float) (i + 1) / 5)));
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius[i], mOutterRingPaint);
}
}
執行效果見gif,至此我們就完成了水波紋自定義View
的開發,怎麼樣?是不是很有趣啊.