NumberProgressBar:一个简约性感的数字ProgressBar

原生的ProgressBar在不同的主题下风格迥异,有矩形条状的,有代表加载进行中的圆圈风格的,在4.0的holo风格下这些ProgressBar都还比较好看,但是在非holo风格下让人厌烦。我不排斥使用原生控件,但是有时我们的app可能比较个性化,需要更有个性的ProgressBar。

下面这款开源ProgressBar就比较有个性。

NumberProgressBar


github地址 https://github.com/daimajia/NumberProgressBar

该控件虽然也叫ProgressBar,但是和sdk中的ProgressBar控件没有任何继承关系,直接继承子view。控件分为三部分,如图:



用法:

xml中

1
2
3
4
<com.daimajia.numberprogressbar.NumberProgressBar
     android:id= "@+id/number_progress_bar"
     style= "@style/NumberProgressBar_Default"
/>

除了默认的style,你还可以设置成如下style:

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

比如默认情况下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
final NumberProgressBar bnp = (NumberProgressBar)findViewById(R.id.numberbar1);
counter = 0;
timer = new Timer();
timer.schedule( new TimerTask() {
     @Override
     public void run() {
         runOnUiThread( new Runnable() {
             @Override
             public void run() {
                 bnp.incrementProgressBy(1);
                 counter ++;
                 if (counter == 110) {
                     bnp.setProgress(0);
                     counter=0;
                 }
             }
         });
     }
}, 1000, 100);

incrementProgressBy表示Progress在现有基础上增加多少,从上面的代码可以看出,demo中NumberProgressBar的动态增加是采用timer实现的,也可以用属性动画来实现,当然在现实运用中可能是一些跟网络有关的事件来实现。

NumberProgressBar的源码实现:

如果你已经学会了如何自定义一个view,那么NumberProgressBar的代码是很容易看懂的。这里想指出的是有个细节我个人持保留意见,那就是作者在onMeasure方法中调用了自己实现的measure方法,在View的绘制中是先measure然后再在measure方法中调用onMeasure,而继承子view的子类一般只重写onMeasure方法。虽然这里并不会引起什么错误,但是我觉得还是遵守view的绘制流程比较好。

最后贴出NumberProgressBar的java部分的代码,代码不多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
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();
     }
     @Override
     protected int getSuggestedMinimumWidth() {
         return (int)mTextSize;
     }
     @Override
     protected int getSuggestedMinimumHeight() {
         return Math.max((int)mTextSize,Math.max((int)mReachedBarHeight,(int)mUnreachedBarHeight));
     }
     @Override
     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;
     }
     @Override
     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();
         }
     }
     @Override
     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;
     }
     @Override
     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();
     }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值