Android custom display progress bar button

Keywords: Android github xml less

Some App s can show progress when they click the download button. We can implement the button with the progress bar by inheriting the native Button and rewriting onDraw.

Github: https://github.com/imcloudfloating/DesignApp

 

1. effect:

2. principle:

Create three Gradient Drawables as button background, progress bar background and progress bar foreground, set the width by calculating the percentage of progress bar, and then call invalidate() to redraw. Gradient Drawable sets parameters such as color, roundness and so on. Of course, you can also load xml directly as the background.

3. Custom parameters:

Create an attrs.xml file in the values directory

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3 
 4     <attr name="progressColor" format="color" />
 5     <attr name="progressBackColor" format="color" />
 6     <attr name="progress" format="integer" />
 7     <attr name="minProgress" format="integer" />
 8     <attr name="maxProgress" format="integer" />
 9 
10     <declare-styleable name="ProgressButton">
11         <attr name="progressColor" />
12         <attr name="progressBackColor" />
13         <attr name="buttonColor" format="color" />
14         <attr name="cornerRadius" format="dimension" />
15         <attr name="progress" />
16         <attr name="minProgress" />
17         <attr name="maxProgress" />
18         <attr name="progressMargin" format="dimension" />
19     </declare-styleable>
20 
21 </resources>

3. Button class:

In the setProgress method, change the value of mProgress, and then call invalidate() to redraw, because I define a minProgress (default is 0), so when calculating the width of the progress bar, the current progress and maximum progress are subtracted from minProgress before division.

if (progressWidth < mCornerRadius * 2) {
progressWidth = mCornerRadius * 2;
}
When the width of the progress bar is less than 2 times the radius of the roundness, the roundness of the progress bar is not consistent with the roundness of the background, so the code above is added.
Getting the width and height is also possible with getWidth() and getHeight(), but the effect is not visible in the designer, so I used getMeasuredWidth() and getMeasuredHeight().
  1 package com.cloud.customviews;
  2 
  3 import android.content.Context;
  4 import android.content.res.TypedArray;
  5 import android.graphics.Canvas;
  6 import android.graphics.drawable.GradientDrawable;
  7 import android.support.v7.widget.AppCompatButton;
  8 import android.util.AttributeSet;
  9 
 10 public class ProgressButton extends AppCompatButton {
 11 
 12     private float mCornerRadius = 0;
 13     private float mProgressMargin = 0;
 14 
 15     private boolean mFinish;
 16 
 17     private int mProgress;
 18     private int mMaxProgress = 100;
 19     private int mMinProgress = 0;
 20 
 21     private GradientDrawable mDrawableButton;
 22     private GradientDrawable mDrawableProgressBackground;
 23     private GradientDrawable mDrawableProgress;
 24 
 25     public ProgressButton(Context context, AttributeSet attrs) {
 26         super(context, attrs);
 27         initialize(context, attrs);
 28     }
 29 
 30     public ProgressButton(Context context, AttributeSet attrs, int defStyle) {
 31         super(context, attrs, defStyle);
 32         initialize(context, attrs);
 33     }
 34 
 35     private void initialize(Context context, AttributeSet attrs) {
 36         //Progress background drawable
 37         mDrawableProgressBackground = new GradientDrawable();
 38         //Progress drawable
 39         mDrawableProgress = new GradientDrawable();
 40         //Normal drawable
 41         mDrawableButton = new GradientDrawable();
 42 
 43         //Get default normal color
 44         int defaultButtonColor = getResources().getColor(R.color.colorGray, null);
 45         //Get default progress color
 46         int defaultProgressColor = getResources().getColor(R.color.colorGreen, null);
 47         //Get default progress background color
 48         int defaultBackColor = getResources().getColor(R.color.colorGray, null);
 49 
 50         TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.ProgressButton);
 51 
 52         try {
 53             mProgressMargin = attr.getDimension(R.styleable.ProgressButton_progressMargin, mProgressMargin);
 54             mCornerRadius = attr.getDimension(R.styleable.ProgressButton_cornerRadius, mCornerRadius);
 55             //Get custom normal color
 56             int buttonColor = attr.getColor(R.styleable.ProgressButton_buttonColor, defaultButtonColor);
 57             //Set normal color
 58             mDrawableButton.setColor(buttonColor);
 59             //Get custom progress background color
 60             int progressBackColor = attr.getColor(R.styleable.ProgressButton_progressBackColor, defaultBackColor);
 61             //Set progress background drawable color
 62             mDrawableProgressBackground.setColor(progressBackColor);
 63             //Get custom progress color
 64             int progressColor = attr.getColor(R.styleable.ProgressButton_progressColor, defaultProgressColor);
 65             //Set progress drawable color
 66             mDrawableProgress.setColor(progressColor);
 67 
 68             //Get default progress
 69             mProgress = attr.getInteger(R.styleable.ProgressButton_progress, mProgress);
 70             //Get minimum progress
 71             mMinProgress = attr.getInteger(R.styleable.ProgressButton_minProgress, mMinProgress);
 72             //Get maximize progress
 73             mMaxProgress = attr.getInteger(R.styleable.ProgressButton_maxProgress, mMaxProgress);
 74 
 75         } finally {
 76             attr.recycle();
 77         }
 78 
 79         //Set corner radius
 80         mDrawableButton.setCornerRadius(mCornerRadius);
 81         mDrawableProgressBackground.setCornerRadius(mCornerRadius);
 82         mDrawableProgress.setCornerRadius(mCornerRadius - mProgressMargin);
 83         setBackgroundDrawable(mDrawableButton);
 84 
 85         mFinish = false;
 86     }
 87 
 88     @Override
 89     protected void onDraw(Canvas canvas) {
 90         if (mProgress > mMinProgress && mProgress <= mMaxProgress && !mFinish) {
 91             //Calculate the width of progress
 92             float progressWidth =
 93                     (float) getMeasuredWidth() * ((float) (mProgress - mMinProgress) / mMaxProgress - mMinProgress);
 94 
 95             //If progress width less than 2x corner radius, the radius of progress will be wrong
 96             if (progressWidth < mCornerRadius * 2) {
 97                 progressWidth = mCornerRadius * 2;
 98             }
 99 
100             //Set rect of progress
101             mDrawableProgress.setBounds((int) mProgressMargin, (int) mProgressMargin,
102                     (int) (progressWidth - mProgressMargin), getMeasuredHeight() - (int) mProgressMargin);
103 
104             //Draw progress
105             mDrawableProgress.draw(canvas);
106 
107             if (mProgress == mMaxProgress) {
108                 setBackgroundDrawable(mDrawableButton);
109                 mFinish = true;
110             }
111         }
112         super.onDraw(canvas);
113     }
114 
115     /**
116      * Set current progress
117      */
118     public void setProgress(int progress) {
119         if (!mFinish) {
120             mProgress = progress;
121             setBackgroundDrawable(mDrawableProgressBackground);
122             invalidate();
123         }
124     }
125 
126     public void setMaxProgress(int maxProgress) {
127         mMaxProgress = maxProgress;
128     }
129 
130     public void setMinProgress(int minProgress) {
131         mMinProgress = minProgress;
132     }
133 
134     public void reset() {
135         mFinish = false;
136         mProgress = mMinProgress;
137     }
138 }

Posted by gregtel on Thu, 24 Jan 2019 00:00:14 -0800