Android自定義View之炫麗的進度條
好久沒有寫Blog了,昨天意外看到自己無意中寫的一篇文章,訪問量都有1k+,突然之間覺得寫博客,分享知識是一件多麼幸福的事情!今天我給大家分享一個自定義view來繪製一個項目中經常用的炫麗立體效果的進度條.雖然不怎麼有難度,但是項目中經常用到,希望能幫助大家項目中的一些問題,幫到大家。
代碼下載地址:http://download.csdn.net/detail/zgkxzx/9762403
實現原理
主要是通過Paint的setXfermode(Xfermode xfermode) 圖像混合模式,關於paint的混合模式的知識,小編就不在這裏科普了,自己到百度上面谷歌一下就知道了。下面我們找重點的地方講解。如下,多種混合模式的效果圖:
這裏,我們用的的模式是SRC_IN,從效果圖中,我們很清晰看出,當SRC是藍色正方形圖片,DST爲橙色圓形圖片時,SRC_IN效果,即爲當SRC與DST重疊發生,交集部分爲兩圖交集區域,並展現出SRC交集區域。這裏,我們項目中SRC爲
DST資源爲通過畫布畫的扇形圖像,由於圖片源SRC是一張切圖,我們不容易控制進度,那麼我們通過控制扇形的區域,來實現整體畫布的進度條的控制。如下圖,沒有找到比較好的作圖工具,自己用Galaxy Note機手繪圖形進行分析(畫的不好,不要吐槽~~)。
當DST扇形(紅色區域)在畫布上掃過,與SRC的交集部分,即畫布上面最終展現的區域(紫色區域),這裏的扇形起始邊是-270度。我們可以根據實際需要進行調整。好了,我們不多說了,直接上源碼分析。
代碼實現
自定義View的步驟一般是onMeasure,onLayout,onDraw,這裏我們只需要測量和繪製就行了。
第一步:初始化參數
//背景圖片和進度條圖片
private Bitmap bgBmp;
private Bitmap bgProcess;
private PorterDuffXfermode mMode;
private Paint mXferPaint;
private RectF mOval;
private Paint mTextPaint;
//百分比
private int mPercent;
//邊長
private int sideLength;
//縮放比例
private float scale = 1.0f;
private void init() {
bgBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ring_bg);
if (processImg != null) {
bgProcess = ((BitmapDrawable) processImg).getBitmap();
} else
bgProcess = BitmapFactory.decodeResource(getResources(), R.mipmap.ring_bg_1);
mMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
mXferPaint = new Paint();
mXferPaint.setColor(Color.GREEN);
mXferPaint.setXfermode(mMode);
mXferPaint.setAntiAlias(true);
mOval = new RectF();
mOval.left = 0;
mOval.top = 0;
mPercent = 0;
mTextPaint = new Paint();
mTextPaint.setColor(textColor);
mTextPaint.setTextSize(textSize);
mTextPaint.setAntiAlias(true);
Typeface font = Typeface.createFromAsset(context.getAssets(), textFont != null ? textFont : DEFAULR_FONT);
mTextPaint.setTypeface(font);
}
在初始化中,主要是對需要繪畫的幾個畫筆進行了初始化。這裏比較重要的是我們用的的PorterDuffXfermode混合圖像模式,在這裏採用了SRC_IN模式。畫筆畫出的扇形和原始進度條圖片發生交集後,顯示原始進度條圖片的部分。在設計進度條之前,小編考慮到可擴展性,本來是準備採用DST_IN模式,這樣進度條顯示部分爲交集的扇形部分,這樣進度條的顏色通過xml倒是很方便配置,但是進度條通過drawArc方法畫出來的是屏幕效果圖,效果沒有切片能展現立體的效果。
第二步:onMeasure方法實現測量
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
int bgWidth = bgBmp.getWidth();
int bgHight = bgBmp.getHeight();
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width = bgWidth;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
height = bgHight;
}
//得到邊長,這裏默認進度條爲正方形的控件
sideLength = Math.min(width, height);
//計算比例縮放係數
scale = (float) sideLength / bgWidth;
setMeasuredDimension(sideLength, sideLength);
在測量部分,如果採用包裹方式,控件的大小爲原切片背景大大小;如果EXACTLY方式,那麼原切片貨更加精確的長寬進行比例縮放。
第三步:關鍵部分onDraw方法的實現
//矩陣運算 主要是根據xml的設置對原切片進行比例縮放
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
mXferPaint.setXfermode(null);
canvas.drawBitmap(bgBmp, matrix, mXferPaint);
//將繪製操作保存到新的圖層(離屏緩存)
int saveCount = canvas.saveLayer(0, 0, sideLength, sideLength, null, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
mOval.left = 0;
mOval.top = 0;
mOval.right = sideLength;
mOval.bottom = sideLength;
mXferPaint.setXfermode(null);
//繪製扇形區域,關於-235,290這個角度,根據實際切片的角度填寫,找美工妹子要就行了~~~
canvas.drawArc(mOval, -235, 290 * mPercent / MAX_PROCESS, true, mXferPaint);
mXferPaint.setXfermode(mMode);
canvas.drawBitmap(bgProcess, matrix, mXferPaint);
//繪製進度字
String text = mPercent + "";
canvas.drawText(text, 0, text.length(),
sideLength / 2 - ViewUtil.getTextWidth(mTextPaint, text) / 2,
sideLength / 2 + ViewUtil.getTextHeight(mTextPaint, text) / 2,
mTextPaint);
canvas.restoreToCount(saveCount);
至此,代碼部分也說完了,此自定義view並不怎麼複雜,但是工程中經常用到,希望能幫到大家,一起學習進步…
本來是準備代碼在Github和csdn各上傳一份便於大家參考,可惜最近Github連接不上去了。
代碼下載地址:http://download.csdn.net/detail/zgkxzx/9762403