1.系統(tǒng)ProgressBar樣式實(shí)現(xiàn)原理分析
普通的一直圓形轉(zhuǎn)的ProgressBar
<style name="Widget.ProgressBar">
<item name="indeterminateOnly">true</item>
<item name="indeterminateDrawable">@drawable/progress_medium_white</item>
<item name="indeterminateBehavior">repeat</item>
<item name="indeterminateDuration">3500</item>
<item name="minWidth">48dip</item>
<item name="maxWidth">48dip</item>
<item name="minHeight">48dip</item>
<item name="maxHeight">48dip</item>
<item name="mirrorForRtl">false</item>
</style>
上面的“@drawable/progress_medium_white” 是一個(gè)幀動(dòng)畫
水平的ProgressBar
<style name="Widget.ProgressBar.Horizontal">
<item name="indeterminateOnly">false</item>
<item name="progressDrawable">@drawable/progress_horizontal</item>
<item name="indeterminateDrawable">@drawable/progress_indeterminate_horizontal</item>
<item name="minHeight">20dip</item>
<item name="maxHeight">20dip</item>
<item name="mirrorForRtl">true</item>
</style>
@drawable/progress_indeterminate_horizontal:是一個(gè)幀動(dòng)畫
@drawable/progress_horizontal:是一個(gè)LayerDrawable蔓倍,主要由一個(gè)表示底色的Drawable宇整,和表示Progress的ClipDrawable組成
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
.....................
/>
</shape>
</item>
....................
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
.....................
/>
</shape>
</clip>
</item>
</layer-list>
小結(jié):
一直旋轉(zhuǎn)的系統(tǒng)ProgressBar翎嫡,其實(shí)只是一直播放的幀動(dòng)畫
水平的ProgressBar,是由于ClipDrawable根據(jù)Progress蚌吸,從而改變ClipDrawable的Level
2.方案選擇
- 參考系統(tǒng)水平ProgressBar的樣式實(shí)現(xiàn),自定義特殊的Drawable塞弊,傳入ProgressBar(由于是系統(tǒng)實(shí)現(xiàn)贸辈,優(yōu)先考慮)
- 繼承ProgressBar,重寫里面的Draw方法
3.方案一
- 自定義一個(gè)Drawable碰逸,重寫里面的Draw方法乡小,繪制一個(gè)圓角矩形作為底色
- 再自定義一個(gè)Drawable,重寫里面的Draw方法饵史,根據(jù)Level值满钟,繪制一個(gè)當(dāng)前的進(jìn)度
- 通過LayerDrawable把這兩個(gè)Drawable層疊起來(lái),得到最后的LayerDrawable
- 調(diào)用ProgressBar的setProgressDrawable约急,設(shè)置該LayerDrawable
結(jié)果:失敗零远。通過代碼調(diào)用ProgressBar的setProgressDrawable發(fā)現(xiàn)調(diào)用無(wú)效苗分,不解厌蔽。
4.方案二
- 生成一個(gè)矩形:RectF rectF = new RectF(mPathWidth,mPathWidth,getWidth()-mPathWidth,getHeight()-mPathWidth);
注意:因?yàn)槭侵灰吙颍陨傻木匦我獪p去邊框的寬度 - 生成圓角矩形的Path
- 利用PathMeasure摔癣,獲取Path的某一部分奴饮,并繪制到Canvas
public class RoundCornerProgressBar extends ProgressBar {
private Paint mBackgroundPaint = new Paint();
private Paint mProgressPaint = new Paint();
private float mRadius;
private int mPathWidth;
private float mStartOffsetPercent;
構(gòu)造函數(shù)(略)
@Override
public void onDraw(Canvas canvas) {
drawBackground(canvas);
drawProgress(canvas);
}
private void drawBackground(Canvas canvas){
RectF rectF = new RectF(mPathWidth,mPathWidth,getWidth()-mPathWidth,getHeight()-mPathWidth);
canvas.drawRoundRect(rectF, mRadius, mRadius, mBackgroundPaint);
}
private void drawProgress(Canvas canvas){
RectF rectF = new RectF(mPathWidth,mPathWidth,getWidth()-mPathWidth,getHeight()-mPathWidth);
Path path = new Path();
path.addRoundRect(rectF, mRadius, mRadius, Path.Direction.CW);
Path mRenderPaths = new Path();
PathMeasure mPathMeasure = new PathMeasure(path, false);
float pathOffset = mPathMeasure.getLength() * (getProgress()/100f);
float startOffset = mPathMeasure.getLength() * mStartOffsetPercent;
if(pathOffset + startOffset < mPathMeasure.getLength()){
if (mPathMeasure.getSegment(startOffset, startOffset + pathOffset, mRenderPaths, true)) {
canvas.drawPath(mRenderPaths, mProgressPaint);
}
} else {
if (mPathMeasure.getSegment(startOffset, mPathMeasure.getLength(), mRenderPaths, true)) {
canvas.drawPath(mRenderPaths, mProgressPaint);
}
if (mPathMeasure.getSegment(0, pathOffset + startOffset - mPathMeasure.getLength(), mRenderPaths, true)) {
canvas.drawPath(mRenderPaths, mProgressPaint);
}
}
}
}