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 }