轉自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0813/1645.html
原生的ProgressBar在不同的主題下風格迥異,有矩形條狀的,有代表加載進行中的圓圈風格的,在4.0的holo風格下這些ProgressBar都還比較好看,但是在非holo風格下讓人厭煩。我不排斥使用原生控件,但是有時我們的app可能比較個性化,需要更有個性的ProgressBar。
下面這款開源ProgressBar就比較有個性。
NumberProgressBar
github地址 https://github.com/daimajia/NumberProgressBar
該控件雖然也叫ProgressBar,但是和sdk中的ProgressBar控件沒有任何繼承關系,直接繼承子view。控件分為三部分,如圖:
用法:
xml中
-
<com.daimajia.numberprogressbar.NumberProgressBar
-
android:id="@+id/number_progress_bar"
-
style="@style/NumberProgressBar_Default" />
NumberProgressBar_Default
NumberProgressBar_Passing_Green
NumberProgressBar_Relax_Blue
NumberProgressBar_Grace_Yellow
NumberProgressBar_Warning_Red
NumberProgressBar_Funny_Orange
NumberProgressBar_Beauty_Red
NumberProgressBar_Twinkle_Night
對應的外觀如下:
除了直接用已經定義好的style,你還可以通過設置屬性來改變外觀。
NumberProgressBar的一些屬性:
reached area和unreached area
-
顏色
-
高度
文字部分,描述進程的百分比數字
-
顏色
-
字體大小
-
是否可見
-
和reached area與unreached area之間的距離
整個bar
-
最大進度 max progress
-
當前進度 current progress
比如默認情況下
-
<com.daimajia.numberprogressbar.NumberProgressBar
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
custom:progress_unreached_color="#CCCCCC"
-
custom:progress_reached_color="#3498DB"
-
custom:progress_unreached_bar_height="0.75dp"
-
custom:progress_reached_bar_height="1.5dp"
-
custom:progress_text_size="10sp"
-
custom:progress_text_color="#3498DB"
-
custom:progress_text_offset="1dp"
-
custom:progress_text_visibility="visible"
-
custom:max="100"
-
custom:progress="80" />
如上面的第一張圖所示,github項目中的demo實現了NumberProgressBar的動畫效果,但是這個動畫效果並不是NumberProgressBar自帶的,而是在外部通過不斷調用setProgress做到的,demo中
-
final NumberProgressBar bnp = (NumberProgressBar)findViewById(R.id.numberbar1);
-
counter = 0;
-
timer = new Timer();
-
timer.schedule( new TimerTask() {
-
-
public void run() {
-
runOnUiThread( new Runnable() {
-
-
public void run() {
-
bnp.incrementProgressBy( 1);
-
counter ++;
-
if (counter == 110) {
-
bnp.setProgress( 0);
-
counter= 0;
-
}
-
}
-
});
-
}
-
}, 1000, 100);
NumberProgressBar的源碼實現:
如果你已經學會了如何自定義一個view,那么NumberProgressBar的代碼是很容易看懂的。這里想指出的是有個細節我個人持保留意見,那就是作者在onMeasure方法中調用了自己實現的measure方法,在View的繪制中是先measure然后再在measure方法中調用onMeasure,而繼承子view的子類一般只重寫onMeasure方法。雖然這里並不會引起什么錯誤,但是我覺得還是遵守view的繪制流程比較好。
最后貼出NumberProgressBar的java部分的代碼,代碼不多:
-
package com.daimajia.numberprogressbar;
-
import android.content.Context;
-
import android.content.res.TypedArray;
-
import android.graphics.Canvas;
-
import android.graphics.Color;
-
import android.graphics.Paint;
-
import android.graphics.RectF;
-
import android.os.Bundle;
-
import android.os.Parcelable;
-
import android.util.AttributeSet;
-
import android.view.View;
-
/**
-
* Created by daimajia on 14-4-30.
-
*/
-
public class NumberProgressBar extends View {
-
private Context mContext;
-
/**
-
* The max progress, default is 100
-
*/
-
private int mMax = 100;
-
/**
-
* current progress, can not exceed the max progress.
-
*/
-
private int mProgress = 0;
-
/**
-
* the progress area bar color
-
*/
-
private int mReachedBarColor;
-
/**
-
* the bar unreached area color.
-
*/
-
private int mUnreachedBarColor;
-
/**
-
* the progress text color.
-
*/
-
private int mTextColor;
-
/**
-
* the progress text size
-
*/
-
private float mTextSize;
-
/**
-
* the height of the reached area
-
*/
-
private float mReachedBarHeight;
-
/**
-
* the height of the unreached area
-
*/
-
private float mUnreachedBarHeight;
-
private final int default_text_color = Color.rgb(66, 145, 241);
-
private final int default_reached_color = Color.rgb(66,145,241);
-
private final int default_unreached_color = Color.rgb(204, 204, 204);
-
private final float default_progress_text_offset;
-
private final float default_text_size;
-
private final float default_reached_bar_height;
-
private final float default_unreached_bar_height;
-
/**
-
* for save and restore instance of progressbar.
-
*/
-
private static final String INSTANCE_STATE = "saved_instance";
-
private static final String INSTANCE_TEXT_COLOR = "text_color";
-
private static final String INSTANCE_TEXT_SIZE = "text_size";
-
private static final String INSTANCE_REACHED_BAR_HEIGHT = "reached_bar_height";
-
private static final String INSTANCE_REACHED_BAR_COLOR = "reached_bar_color";
-
private static final String INSTANCE_UNREACHED_BAR_HEIGHT = "unreached_bar_height";
-
private static final String INSTANCE_UNREACHED_BAR_COLOR = "unreached_bar_color";
-
private static final String INSTANCE_MAX = "max";
-
private static final String INSTANCE_PROGRESS = "progress";
-
private static final int PROGRESS_TEXT_VISIBLE = 0;
-
private static final int PROGRESS_TEXT_INVISIBLE = 1;
-
/**
-
* the width of the text that to be drawn
-
*/
-
private float mDrawTextWidth;
-
/**
-
* the drawn text start
-
*/
-
private float mDrawTextStart;
-
/**
-
*the drawn text end
-
*/
-
private float mDrawTextEnd;
-
/**
-
* the text that to be drawn in onDraw()
-
*/
-
private String mCurrentDrawText;
-
/**
-
* the Paint of the reached area.
-
*/
-
private Paint mReachedBarPaint;
-
/**
-
* the Painter of the unreached area.
-
*/
-
private Paint mUnreachedBarPaint;
-
/**
-
* the Painter of the progress text.
-
*/
-
private Paint mTextPaint;
-
/**
-
* Unreached Bar area to draw rect.
-
*/
-
private RectF mUnreachedRectF = new RectF(0,0,0,0);
-
/**
-
* reached bar area rect.
-
*/
-
private RectF mReachedRectF = new RectF(0,0,0,0);
-
/**
-
* the progress text offset.
-
*/
-
private float mOffset;
-
/**
-
* determine if need to draw unreached area
-
*/
-
private boolean mDrawUnreachedBar = true;
-
private boolean mDrawReachedBar = true;
-
private boolean mIfDrawText = true;
-
public enum ProgressTextVisibility{
-
Visible,Invisible
-
};
-
public NumberProgressBar(Context context) {
-
this(context, null);
-
}
-
public NumberProgressBar(Context context, AttributeSet attrs) {
-
this(context, attrs, R.attr.numberProgressBarStyle);
-
}
-
public NumberProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
-
super(context, attrs, defStyleAttr);
-
mContext = context;
-
default_reached_bar_height = dp2px( 1.5f);
-
default_unreached_bar_height = dp2px( 1.0f);
-
default_text_size = sp2px( 10);
-
default_progress_text_offset = dp2px( 3.0f);
-
//load styled attributes.
-
final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.NumberProgressBar,
-
defStyleAttr, 0);
-
mReachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_reached_color, default_reached_color);
-
mUnreachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_unreached_color,default_unreached_color);
-
mTextColor = attributes.getColor(R.styleable.NumberProgressBar_progress_text_color,default_text_color);
-
mTextSize = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_size, default_text_size);
-
mReachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_reached_bar_height,default_reached_bar_height);
-
mUnreachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_unreached_bar_height,default_unreached_bar_height);
-
mOffset = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_offset,default_progress_text_offset);
-
int textVisible = attributes.getInt(R.styleable.NumberProgressBar_progress_text_visibility,PROGRESS_TEXT_VISIBLE);
-
if(textVisible != PROGRESS_TEXT_VISIBLE){
-
mIfDrawText = false;
-
}
-
setProgress(attributes.getInt(R.styleable.NumberProgressBar_progress, 0));
-
setMax(attributes.getInt(R.styleable.NumberProgressBar_max, 100));
-
//
-
attributes.recycle();
-
initializePainters();
-
}
-
-
protected int getSuggestedMinimumWidth() {
-
return (int)mTextSize;
-
}
-
-
protected int getSuggestedMinimumHeight() {
-
return Math.max((int)mTextSize,Math.max((int)mReachedBarHeight,(int)mUnreachedBarHeight));
-
}
-
-
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec,false));
-
}
-
private int measure(int measureSpec,boolean isWidth){
-
int result;
-
int mode = MeasureSpec.getMode(measureSpec);
-
int size = MeasureSpec.getSize(measureSpec);
-
int padding = isWidth?getPaddingLeft()+getPaddingRight():getPaddingTop()+getPaddingBottom();
-
if(mode == MeasureSpec.EXACTLY){
-
result = size;
-
} else{
-
result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight();
-
result += padding;
-
if(mode == MeasureSpec.AT_MOST){
-
if(isWidth) {
-
result = Math.max(result, size);
-
}
-
else{
-
result = Math.min(result, size);
-
}
-
}
-
}
-
return result;
-
}
-
-
protected void onDraw(Canvas canvas) {
-
if(mIfDrawText){
-
calculateDrawRectF();
-
} else{
-
calculateDrawRectFWithoutProgressText();
-
}
-
if(mDrawReachedBar){
-
canvas.drawRect(mReachedRectF,mReachedBarPaint);
-
}
-
if(mDrawUnreachedBar) {
-
canvas.drawRect(mUnreachedRectF, mUnreachedBarPaint);
-
}
-
if(mIfDrawText)
-
canvas.drawText(mCurrentDrawText,mDrawTextStart,mDrawTextEnd,mTextPaint);
-
}
-
private void initializePainters(){
-
mReachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
mReachedBarPaint.setColor(mReachedBarColor);
-
mUnreachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
mUnreachedBarPaint.setColor(mUnreachedBarColor);
-
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
mTextPaint.setColor(mTextColor);
-
mTextPaint.setTextSize(mTextSize);
-
}
-
private void calculateDrawRectFWithoutProgressText(){
-
mReachedRectF.left = getPaddingLeft();
-
mReachedRectF.top = getHeight()/ 2.0f - mReachedBarHeight / 2.0f;
-
mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight() )/(getMax()* 1.0f) * getProgress() + getPaddingLeft();
-
mReachedRectF.bottom = getHeight()/ 2.0f + mReachedBarHeight / 2.0f;
-
mUnreachedRectF.left = mReachedRectF.right;
-
mUnreachedRectF.right = getWidth() - getPaddingRight();
-
mUnreachedRectF.top = getHeight()/ 2.0f + - mUnreachedBarHeight / 2.0f;
-
mUnreachedRectF.bottom = getHeight()/ 2.0f + mUnreachedBarHeight / 2.0f;
-
}
-
private void calculateDrawRectF(){
-
mCurrentDrawText = String.format( "%d%%",getProgress()*100/getMax());
-
mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText);
-
if(getProgress() == 0){
-
mDrawReachedBar = false;
-
mDrawTextStart = getPaddingLeft();
-
} else{
-
mDrawReachedBar = true;
-
mReachedRectF.left = getPaddingLeft();
-
mReachedRectF.top = getHeight()/ 2.0f - mReachedBarHeight / 2.0f;
-
mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight() )/(getMax()* 1.0f) * getProgress() - mOffset + getPaddingLeft();
-
mReachedRectF.bottom = getHeight()/ 2.0f + mReachedBarHeight / 2.0f;
-
mDrawTextStart = (mReachedRectF.right + mOffset);
-
}
-
mDrawTextEnd = ( int) ((getHeight() / 2.0f) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2.0f)) ;
-
if((mDrawTextStart + mDrawTextWidth )>= getWidth() - getPaddingRight()){
-
mDrawTextStart = getWidth() - getPaddingRight() - mDrawTextWidth;
-
mReachedRectF.right = mDrawTextStart - mOffset;
-
}
-
float unreachedBarStart = mDrawTextStart + mDrawTextWidth + mOffset;
-
if(unreachedBarStart >= getWidth() - getPaddingRight()){
-
mDrawUnreachedBar = false;
-
} else{
-
mDrawUnreachedBar = true;
-
mUnreachedRectF.left = unreachedBarStart;
-
mUnreachedRectF.right = getWidth() - getPaddingRight();
-
mUnreachedRectF.top = getHeight()/ 2.0f + - mUnreachedBarHeight / 2.0f;
-
mUnreachedRectF.bottom = getHeight()/ 2.0f + mUnreachedBarHeight / 2.0f;
-
}
-
}
-
/**
-
* get progress text color
-
* @return progress text color
-
*/
-
public int getTextColor() {
-
return mTextColor;
-
}
-
/**
-
* get progress text size
-
* @return progress text size
-
*/
-
public float getProgressTextSize() {
-
return mTextSize;
-
}
-
public int getUnreachedBarColor() {
-
return mUnreachedBarColor;
-
}
-
public int getReachedBarColor() {
-
return mReachedBarColor;
-
}
-
public int getProgress() {
-
return mProgress;
-
}
-
public int getMax() {
-
return mMax;
-
}
-
public float getReachedBarHeight(){
-
return mReachedBarHeight;
-
}
-
public float getUnreachedBarHeight(){
-
return mUnreachedBarHeight;
-
}
-
public void setProgressTextSize(float TextSize) {
-
this.mTextSize = TextSize;
-
mTextPaint.setTextSize(mTextSize);
-
invalidate();
-
}
-
public void setProgressTextColor(int TextColor) {
-
this.mTextColor = TextColor;
-
mTextPaint.setColor(mTextColor);
-
invalidate();
-
}
-
public void setUnreachedBarColor(int BarColor) {
-
this.mUnreachedBarColor = BarColor;
-
mUnreachedBarPaint.setColor(mReachedBarColor);
-
invalidate();
-
}
-
public void setReachedBarColor(int ProgressColor) {
-
this.mReachedBarColor = ProgressColor;
-
mReachedBarPaint.setColor(mReachedBarColor);
-
invalidate();
-
}
-
public void setMax(int Max) {
-
if(Max > 0){
-
this.mMax = Max;
-
invalidate();
-
}
-
}
-
public void incrementProgressBy(int by){
-
if(by > 0){
-
setProgress(getProgress() + by);
-
}
-
}
-
public void setProgress(int Progress) {
-
if(Progress <= getMax() && Progress >= 0){
-
this.mProgress = Progress;
-
invalidate();
-
}
-
}
-
-
protected Parcelable onSaveInstanceState() {
-
final Bundle bundle = new Bundle();
-
bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
-
bundle.putInt(INSTANCE_TEXT_COLOR,getTextColor());
-
bundle.putFloat(INSTANCE_TEXT_SIZE, getProgressTextSize());
-
bundle.putFloat(INSTANCE_REACHED_BAR_HEIGHT,getReachedBarHeight());
-
bundle.putFloat(INSTANCE_UNREACHED_BAR_HEIGHT,getUnreachedBarHeight());
-
bundle.putInt(INSTANCE_REACHED_BAR_COLOR,getReachedBarColor());
-
bundle.putInt(INSTANCE_UNREACHED_BAR_COLOR,getUnreachedBarColor());
-
bundle.putInt(INSTANCE_MAX,getMax());
-
bundle.putInt(INSTANCE_PROGRESS,getProgress());
-
return bundle;
-
}
-
-
protected void onRestoreInstanceState(Parcelable state) {
-
if(state instanceof Bundle){
-
final Bundle bundle = (Bundle)state;
-
mTextColor = bundle.getInt(INSTANCE_TEXT_COLOR);
-
mTextSize = bundle.getFloat(INSTANCE_TEXT_SIZE);
-
mReachedBarHeight = bundle.getFloat(INSTANCE_REACHED_BAR_HEIGHT);
-
mUnreachedBarHeight = bundle.getFloat(INSTANCE_UNREACHED_BAR_HEIGHT);
-
mReachedBarColor = bundle.getInt(INSTANCE_REACHED_BAR_COLOR);
-
mUnreachedBarColor = bundle.getInt(INSTANCE_UNREACHED_BAR_COLOR);
-
initializePainters();
-
setMax(bundle.getInt(INSTANCE_MAX));
-
setProgress(bundle.getInt(INSTANCE_PROGRESS));
-
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
-
return;
-
}
-
super.onRestoreInstanceState(state);
-
}
-
public float dp2px(float dp) {
-
final float scale = getResources().getDisplayMetrics().density;
-
return dp * scale + 0.5f;
-
}
-
public float sp2px(float sp){
-
final float scale = getResources().getDisplayMetrics().scaledDensity;
-
return sp * scale;
-
}
-
public void setProgressTextVisibility(ProgressTextVisibility visibility){
-
if(visibility == ProgressTextVisibility.Visible){
-
mIfDrawText = true;
-
} else{
-
mIfDrawText = false;
-
}
-
invalidate();
-
}
-