Android 数字进度条NumberProgressBar

 

转自: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中

 

  1.  
    <com.daimajia.numberprogressbar.NumberProgressBar
  2.  
    android:id="@+id/number_progress_bar"
  3.  
    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.  
    <com.daimajia.numberprogressbar.NumberProgressBar
  2.  
    android:layout_width="wrap_content"
  3.  
    android:layout_height="wrap_content"
  4.  
    custom:progress_unreached_color="#CCCCCC"
  5.  
    custom:progress_reached_color="#3498DB"
  6.  
    custom:progress_unreached_bar_height="0.75dp"
  7.  
    custom:progress_reached_bar_height="1.5dp"
  8.  
    custom:progress_text_size="10sp"
  9.  
    custom:progress_text_color="#3498DB"
  10.  
    custom:progress_text_offset="1dp"
  11.  
    custom:progress_text_visibility="visible"
  12.  
    custom:max="100"
  13.  
    custom:progress="80" />
能体现进度的动画效果:

 

如上面的第一张图所示,github项目中的demo实现了NumberProgressBar的动画效果,但是这个动画效果并不是NumberProgressBar自带的,而是在外部通过不断调用setProgress做到的,demo中

 

  1.  
    final NumberProgressBar bnp = (NumberProgressBar)findViewById(R.id.numberbar1);
  2.  
    counter = 0;
  3.  
    timer = new Timer();
  4.  
    timer.schedule(new TimerTask() {
  5.  
    @Override
  6.  
    public void run() {
  7.  
    runOnUiThread(new Runnable() {
  8.  
    @Override
  9.  
    public void run() {
  10.  
    bnp.incrementProgressBy(1);
  11.  
    counter ++;
  12.  
    if (counter == 110) {
  13.  
    bnp.setProgress(0);
  14.  
    counter=0;
  15.  
    }
  16.  
    }
  17.  
    });
  18.  
    }
  19.  
    }, 1000, 100);
incrementProgressBy表示Progress在现有基础上增加多少,从上面的代码可以看出,demo中 NumberProgressBar 的动态增加是采用timer实现的,也可以用属性动画来实现,当然在现实运用中可能是一些跟网络有关的事件来实现。

 

NumberProgressBar的源码实现:

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

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

 

  1.  
    package com.daimajia.numberprogressbar;
  2.  
    import android.content.Context;
  3.  
    import android.content.res.TypedArray;
  4.  
    import android.graphics.Canvas;
  5.  
    import android.graphics.Color;
  6.  
    import android.graphics.Paint;
  7.  
    import android.graphics.RectF;
  8.  
    import android.os.Bundle;
  9.  
    import android.os.Parcelable;
  10.  
    import android.util.AttributeSet;
  11.  
    import android.view.View;
  12.  
    /**
  13.  
    * Created by daimajia on 14-4-30.
  14.  
    */
  15.  
    public class NumberProgressBar extends View {
  16.  
    private Context mContext;
  17.  
    /**
  18.  
    * The max progress, default is 100
  19.  
    */
  20.  
    private int mMax = 100;
  21.  
    /**
  22.  
    * current progress, can not exceed the max progress.
  23.  
    */
  24.  
    private int mProgress = 0;
  25.  
    /**
  26.  
    * the progress area bar color
  27.  
    */
  28.  
    private int mReachedBarColor;
  29.  
    /**
  30.  
    * the bar unreached area color.
  31.  
    */
  32.  
    private int mUnreachedBarColor;
  33.  
    /**
  34.  
    * the progress text color.
  35.  
    */
  36.  
    private int mTextColor;
  37.  
    /**
  38.  
    * the progress text size
  39.  
    */
  40.  
    private float mTextSize;
  41.  
    /**
  42.  
    * the height of the reached area
  43.  
    */
  44.  
    private float mReachedBarHeight;
  45.  
    /**
  46.  
    * the height of the unreached area
  47.  
    */
  48.  
    private float mUnreachedBarHeight;
  49.  
    private final int default_text_color = Color.rgb(66, 145, 241);
  50.  
    private final int default_reached_color = Color.rgb(66,145,241);
  51.  
    private final int default_unreached_color = Color.rgb(204, 204, 204);
  52.  
    private final float default_progress_text_offset;
  53.  
    private final float default_text_size;
  54.  
    private final float default_reached_bar_height;
  55.  
    private final float default_unreached_bar_height;
  56.  
    /**
  57.  
    * for save and restore instance of progressbar.
  58.  
    */
  59.  
    private static final String INSTANCE_STATE = "saved_instance";
  60.  
    private static final String INSTANCE_TEXT_COLOR = "text_color";
  61.  
    private static final String INSTANCE_TEXT_SIZE = "text_size";
  62.  
    private static final String INSTANCE_REACHED_BAR_HEIGHT = "reached_bar_height";
  63.  
    private static final String INSTANCE_REACHED_BAR_COLOR = "reached_bar_color";
  64.  
    private static final String INSTANCE_UNREACHED_BAR_HEIGHT = "unreached_bar_height";
  65.  
    private static final String INSTANCE_UNREACHED_BAR_COLOR = "unreached_bar_color";
  66.  
    private static final String INSTANCE_MAX = "max";
  67.  
    private static final String INSTANCE_PROGRESS = "progress";
  68.  
    private static final int PROGRESS_TEXT_VISIBLE = 0;
  69.  
    private static final int PROGRESS_TEXT_INVISIBLE = 1;
  70.  
    /**
  71.  
    * the width of the text that to be drawn
  72.  
    */
  73.  
    private float mDrawTextWidth;
  74.  
    /**
  75.  
    * the drawn text start
  76.  
    */
  77.  
    private float mDrawTextStart;
  78.  
    /**
  79.  
    *the drawn text end
  80.  
    */
  81.  
    private float mDrawTextEnd;
  82.  
    /**
  83.  
    * the text that to be drawn in onDraw()
  84.  
    */
  85.  
    private String mCurrentDrawText;
  86.  
    /**
  87.  
    * the Paint of the reached area.
  88.  
    */
  89.  
    private Paint mReachedBarPaint;
  90.  
    /**
  91.  
    * the Painter of the unreached area.
  92.  
    */
  93.  
    private Paint mUnreachedBarPaint;
  94.  
    /**
  95.  
    * the Painter of the progress text.
  96.  
    */
  97.  
    private Paint mTextPaint;
  98.  
    /**
  99.  
    * Unreached Bar area to draw rect.
  100.  
    */
  101.  
    private RectF mUnreachedRectF = new RectF(0,0,0,0);
  102.  
    /**
  103.  
    * reached bar area rect.
  104.  
    */
  105.  
    private RectF mReachedRectF = new RectF(0,0,0,0);
  106.  
    /**
  107.  
    * the progress text offset.
  108.  
    */
  109.  
    private float mOffset;
  110.  
    /**
  111.  
    * determine if need to draw unreached area
  112.  
    */
  113.  
    private boolean mDrawUnreachedBar = true;
  114.  
    private boolean mDrawReachedBar = true;
  115.  
    private boolean mIfDrawText = true;
  116.  
    public enum ProgressTextVisibility{
  117.  
    Visible,Invisible
  118.  
    };
  119.  
    public NumberProgressBar(Context context) {
  120.  
    this(context, null);
  121.  
    }
  122.  
    public NumberProgressBar(Context context, AttributeSet attrs) {
  123.  
    this(context, attrs, R.attr.numberProgressBarStyle);
  124.  
    }
  125.  
    public NumberProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
  126.  
    super(context, attrs, defStyleAttr);
  127.  
    mContext = context;
  128.  
    default_reached_bar_height = dp2px(1.5f);
  129.  
    default_unreached_bar_height = dp2px(1.0f);
  130.  
    default_text_size = sp2px(10);
  131.  
    default_progress_text_offset = dp2px(3.0f);
  132.  
    //load styled attributes.
  133.  
    final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.NumberProgressBar,
  134.  
    defStyleAttr, 0);
  135.  
    mReachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_reached_color, default_reached_color);
  136.  
    mUnreachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_unreached_color,default_unreached_color);
  137.  
    mTextColor = attributes.getColor(R.styleable.NumberProgressBar_progress_text_color,default_text_color);
  138.  
    mTextSize = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_size, default_text_size);
  139.  
    mReachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_reached_bar_height,default_reached_bar_height);
  140.  
    mUnreachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_unreached_bar_height,default_unreached_bar_height);
  141.  
    mOffset = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_offset,default_progress_text_offset);
  142.  
    int textVisible = attributes.getInt(R.styleable.NumberProgressBar_progress_text_visibility,PROGRESS_TEXT_VISIBLE);
  143.  
    if(textVisible != PROGRESS_TEXT_VISIBLE){
  144.  
    mIfDrawText = false;
  145.  
    }
  146.  
    setProgress(attributes.getInt(R.styleable.NumberProgressBar_progress,0));
  147.  
    setMax(attributes.getInt(R.styleable.NumberProgressBar_max, 100));
  148.  
    //
  149.  
    attributes.recycle();
  150.  
    initializePainters();
  151.  
    }
  152.  
    @Override
  153.  
    protected int getSuggestedMinimumWidth() {
  154.  
    return (int)mTextSize;
  155.  
    }
  156.  
    @Override
  157.  
    protected int getSuggestedMinimumHeight() {
  158.  
    return Math.max((int)mTextSize,Math.max((int)mReachedBarHeight,(int)mUnreachedBarHeight));
  159.  
    }
  160.  
    @Override
  161.  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  162.  
    setMeasuredDimension(measure(widthMeasureSpec,true), measure(heightMeasureSpec,false));
  163.  
    }
  164.  
    private int measure(int measureSpec,boolean isWidth){
  165.  
    int result;
  166.  
    int mode = MeasureSpec.getMode(measureSpec);
  167.  
    int size = MeasureSpec.getSize(measureSpec);
  168.  
    int padding = isWidth?getPaddingLeft()+getPaddingRight():getPaddingTop()+getPaddingBottom();
  169.  
    if(mode == MeasureSpec.EXACTLY){
  170.  
    result = size;
  171.  
    }else{
  172.  
    result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight();
  173.  
    result += padding;
  174.  
    if(mode == MeasureSpec.AT_MOST){
  175.  
    if(isWidth) {
  176.  
    result = Math.max(result, size);
  177.  
    }
  178.  
    else{
  179.  
    result = Math.min(result, size);
  180.  
    }
  181.  
    }
  182.  
    }
  183.  
    return result;
  184.  
    }
  185.  
    @Override
  186.  
    protected void onDraw(Canvas canvas) {
  187.  
    if(mIfDrawText){
  188.  
    calculateDrawRectF();
  189.  
    }else{
  190.  
    calculateDrawRectFWithoutProgressText();
  191.  
    }
  192.  
    if(mDrawReachedBar){
  193.  
    canvas.drawRect(mReachedRectF,mReachedBarPaint);
  194.  
    }
  195.  
    if(mDrawUnreachedBar) {
  196.  
    canvas.drawRect(mUnreachedRectF, mUnreachedBarPaint);
  197.  
    }
  198.  
    if(mIfDrawText)
  199.  
    canvas.drawText(mCurrentDrawText,mDrawTextStart,mDrawTextEnd,mTextPaint);
  200.  
    }
  201.  
    private void initializePainters(){
  202.  
    mReachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  203.  
    mReachedBarPaint.setColor(mReachedBarColor);
  204.  
    mUnreachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  205.  
    mUnreachedBarPaint.setColor(mUnreachedBarColor);
  206.  
    mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  207.  
    mTextPaint.setColor(mTextColor);
  208.  
    mTextPaint.setTextSize(mTextSize);
  209.  
    }
  210.  
    private void calculateDrawRectFWithoutProgressText(){
  211.  
    mReachedRectF.left = getPaddingLeft();
  212.  
    mReachedRectF.top = getHeight()/2.0f - mReachedBarHeight / 2.0f;
  213.  
    mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight() )/(getMax()*1.0f) * getProgress() + getPaddingLeft();
  214.  
    mReachedRectF.bottom = getHeight()/2.0f + mReachedBarHeight / 2.0f;
  215.  
    mUnreachedRectF.left = mReachedRectF.right;
  216.  
    mUnreachedRectF.right = getWidth() - getPaddingRight();
  217.  
    mUnreachedRectF.top = getHeight()/2.0f + - mUnreachedBarHeight / 2.0f;
  218.  
    mUnreachedRectF.bottom = getHeight()/2.0f + mUnreachedBarHeight / 2.0f;
  219.  
    }
  220.  
    private void calculateDrawRectF(){
  221.  
    mCurrentDrawText = String.format("%d%%",getProgress()*100/getMax());
  222.  
    mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText);
  223.  
    if(getProgress() == 0){
  224.  
    mDrawReachedBar = false;
  225.  
    mDrawTextStart = getPaddingLeft();
  226.  
    }else{
  227.  
    mDrawReachedBar = true;
  228.  
    mReachedRectF.left = getPaddingLeft();
  229.  
    mReachedRectF.top = getHeight()/2.0f - mReachedBarHeight / 2.0f;
  230.  
    mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight() )/(getMax()*1.0f) * getProgress() - mOffset + getPaddingLeft();
  231.  
    mReachedRectF.bottom = getHeight()/2.0f + mReachedBarHeight / 2.0f;
  232.  
    mDrawTextStart = (mReachedRectF.right + mOffset);
  233.  
    }
  234.  
    mDrawTextEnd = (int) ((getHeight() / 2.0f) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2.0f)) ;
  235.  
    if((mDrawTextStart + mDrawTextWidth )>= getWidth() - getPaddingRight()){
  236.  
    mDrawTextStart = getWidth() - getPaddingRight() - mDrawTextWidth;
  237.  
    mReachedRectF.right = mDrawTextStart - mOffset;
  238.  
    }
  239.  
    float unreachedBarStart = mDrawTextStart + mDrawTextWidth + mOffset;
  240.  
    if(unreachedBarStart >= getWidth() - getPaddingRight()){
  241.  
    mDrawUnreachedBar = false;
  242.  
    }else{
  243.  
    mDrawUnreachedBar = true;
  244.  
    mUnreachedRectF.left = unreachedBarStart;
  245.  
    mUnreachedRectF.right = getWidth() - getPaddingRight();
  246.  
    mUnreachedRectF.top = getHeight()/2.0f + - mUnreachedBarHeight / 2.0f;
  247.  
    mUnreachedRectF.bottom = getHeight()/2.0f + mUnreachedBarHeight / 2.0f;
  248.  
    }
  249.  
    }
  250.  
    /**
  251.  
    * get progress text color
  252.  
    * @return progress text color
  253.  
    */
  254.  
    public int getTextColor() {
  255.  
    return mTextColor;
  256.  
    }
  257.  
    /**
  258.  
    * get progress text size
  259.  
    * @return progress text size
  260.  
    */
  261.  
    public float getProgressTextSize() {
  262.  
    return mTextSize;
  263.  
    }
  264.  
    public int getUnreachedBarColor() {
  265.  
    return mUnreachedBarColor;
  266.  
    }
  267.  
    public int getReachedBarColor() {
  268.  
    return mReachedBarColor;
  269.  
    }
  270.  
    public int getProgress() {
  271.  
    return mProgress;
  272.  
    }
  273.  
    public int getMax() {
  274.  
    return mMax;
  275.  
    }
  276.  
    public float getReachedBarHeight(){
  277.  
    return mReachedBarHeight;
  278.  
    }
  279.  
    public float getUnreachedBarHeight(){
  280.  
    return mUnreachedBarHeight;
  281.  
    }
  282.  
    public void setProgressTextSize(float TextSize) {
  283.  
    this.mTextSize = TextSize;
  284.  
    mTextPaint.setTextSize(mTextSize);
  285.  
    invalidate();
  286.  
    }
  287.  
    public void setProgressTextColor(int TextColor) {
  288.  
    this.mTextColor = TextColor;
  289.  
    mTextPaint.setColor(mTextColor);
  290.  
    invalidate();
  291.  
    }
  292.  
    public void setUnreachedBarColor(int BarColor) {
  293.  
    this.mUnreachedBarColor = BarColor;
  294.  
    mUnreachedBarPaint.setColor(mReachedBarColor);
  295.  
    invalidate();
  296.  
    }
  297.  
    public void setReachedBarColor(int ProgressColor) {
  298.  
    this.mReachedBarColor = ProgressColor;
  299.  
    mReachedBarPaint.setColor(mReachedBarColor);
  300.  
    invalidate();
  301.  
    }
  302.  
    public void setMax(int Max) {
  303.  
    if(Max > 0){
  304.  
    this.mMax = Max;
  305.  
    invalidate();
  306.  
    }
  307.  
    }
  308.  
    public void incrementProgressBy(int by){
  309.  
    if(by > 0){
  310.  
    setProgress(getProgress() + by);
  311.  
    }
  312.  
    }
  313.  
    public void setProgress(int Progress) {
  314.  
    if(Progress <= getMax() && Progress >= 0){
  315.  
    this.mProgress = Progress;
  316.  
    invalidate();
  317.  
    }
  318.  
    }
  319.  
    @Override
  320.  
    protected Parcelable onSaveInstanceState() {
  321.  
    final Bundle bundle = new Bundle();
  322.  
    bundle.putParcelable(INSTANCE_STATE,super.onSaveInstanceState());
  323.  
    bundle.putInt(INSTANCE_TEXT_COLOR,getTextColor());
  324.  
    bundle.putFloat(INSTANCE_TEXT_SIZE, getProgressTextSize());
  325.  
    bundle.putFloat(INSTANCE_REACHED_BAR_HEIGHT,getReachedBarHeight());
  326.  
    bundle.putFloat(INSTANCE_UNREACHED_BAR_HEIGHT,getUnreachedBarHeight());
  327.  
    bundle.putInt(INSTANCE_REACHED_BAR_COLOR,getReachedBarColor());
  328.  
    bundle.putInt(INSTANCE_UNREACHED_BAR_COLOR,getUnreachedBarColor());
  329.  
    bundle.putInt(INSTANCE_MAX,getMax());
  330.  
    bundle.putInt(INSTANCE_PROGRESS,getProgress());
  331.  
    return bundle;
  332.  
    }
  333.  
    @Override
  334.  
    protected void onRestoreInstanceState(Parcelable state) {
  335.  
    if(state instanceof Bundle){
  336.  
    final Bundle bundle = (Bundle)state;
  337.  
    mTextColor = bundle.getInt(INSTANCE_TEXT_COLOR);
  338.  
    mTextSize = bundle.getFloat(INSTANCE_TEXT_SIZE);
  339.  
    mReachedBarHeight = bundle.getFloat(INSTANCE_REACHED_BAR_HEIGHT);
  340.  
    mUnreachedBarHeight = bundle.getFloat(INSTANCE_UNREACHED_BAR_HEIGHT);
  341.  
    mReachedBarColor = bundle.getInt(INSTANCE_REACHED_BAR_COLOR);
  342.  
    mUnreachedBarColor = bundle.getInt(INSTANCE_UNREACHED_BAR_COLOR);
  343.  
    initializePainters();
  344.  
    setMax(bundle.getInt(INSTANCE_MAX));
  345.  
    setProgress(bundle.getInt(INSTANCE_PROGRESS));
  346.  
    super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
  347.  
    return;
  348.  
    }
  349.  
    super.onRestoreInstanceState(state);
  350.  
    }
  351.  
    public float dp2px(float dp) {
  352.  
    final float scale = getResources().getDisplayMetrics().density;
  353.  
    return dp * scale + 0.5f;
  354.  
    }
  355.  
    public float sp2px(float sp){
  356.  
    final float scale = getResources().getDisplayMetrics().scaledDensity;
  357.  
    return sp * scale;
  358.  
    }
  359.  
    public void setProgressTextVisibility(ProgressTextVisibility visibility){
  360.  
    if(visibility == ProgressTextVisibility.Visible){
  361.  
    mIfDrawText = true;
  362.  
    }else{
  363.  
    mIfDrawText = false;
  364.  
    }
  365.  
    invalidate();
  366.  
    }
  367.  
posted @ 2020-12-08 11:10  新感觉  阅读(1203)  评论(0编辑  收藏  举报