转自: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();
-
}
-