This post covers a custom button which displays timer in it . Button looks like the below video
To display this, we have to write down a custom implementation of the button. From the above view, we can see its still a button with text, but the additional thing we need to do is styling of button with rounded corners and paint the coundown timer color on the left side.
So my CustomButtonClass looks like
public class CountDownTimerButton extends Button { private boolean mIsSizeChanged; private Paint mPaint; private int mPercent ; private RectF mArcRect; Rect boundingRect = new Rect(); private int mHeight; private int mCircleMargin; public CountDownTimerButton(Context context) { super(context); init(); } public CountDownTimerButton(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CountDownTimerButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @SuppressLint("NewApi") public CountDownTimerButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); setBackgroundResource(R.drawable.selectable_background_button_accent); } /** * Set the percentage of the progress * @param percent */ public void setPercent(int percent) { mPercent = percent; invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); final float startAngle = 270f; final float drawTo = (mPercent * 360/100); if(mArcRect == null || mIsSizeChanged) { getDrawingRect(boundingRect); mHeight = getHeight(); // Left circle which is drawn a bit inside to the button // Offset is the value to move inside mCircleMargin = (int) (mHeight * 0.1); // Arc which is drawn inside with a bit of margin // Offset is the value to move inside int mArcMargin = (int) (mHeight * 0.2); mArcRect = new RectF(); mArcRect.top = boundingRect.top + mArcMargin; mArcRect.bottom = boundingRect.top + mHeight - mArcMargin; mArcRect.left = boundingRect.left + mArcMargin; mArcRect.right = boundingRect.left + mHeight - mArcMargin; } mPaint.setColor(Color.WHITE); canvas.drawCircle(boundingRect.left + mHeight/2, boundingRect.top + mHeight/2, mHeight/2 - mCircleMargin, mPaint); mPaint.setColor(getResources().getColor(R.color.colorAccentDisabled)); canvas.drawArc(mArcRect, startAngle, drawTo, true, mPaint); // Draw a line on Y-Axis, which might help user when progress is 0. canvas.drawLine(mArcRect.right - (mArcRect.right - mArcRect.left)/2, mArcRect.top, mArcRect.right - (mArcRect.right - mArcRect.left)/2, mArcRect.bottom - (mArcRect.bottom - mArcRect.top)/2, mPaint); mIsSizeChanged = false; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mIsSizeChanged = true; super.onSizeChanged(w, h, oldw, oldh); } }
So, All the magic is in onDraw() method. If you closely look at the coundown view, we are drawing a white circle on the left of button and an arc on top of it. setPercent() method is used to update the countdown time. Whenever the text is changed, the cordinates are also changed, so I'm using onSizeChanged() method to determine that scenario and recalculating cordinates in onDraw().
I'm using this component in a fragment and updating the percent based on a timer. Code looks as below.
final int millisInterval = 300; final int totalMinutes = 1; final long totalMillis = totalMinutes * DateUtils.MILLIS_PER_MINUTE; // Countdown timer for updating the remaining time CountDownTimer timer = new CountDownTimer(totalMillis, millisInterval) { @Override public void onTick(long millisUntilFinished) { long millisCompleted = totalMillis - millisUntilFinished; float percent = ((millisCompleted ) / (float)(totalMillis)) * 100; mCoundowntimerBtn.setPercent((int) percent); String formattedTime = DateUtils.formatRemainingTimeToHHMMSS(millisUntilFinished); if(formattedTime != null) { formattedTime = String.format(getString(R.string.time_remaining), formattedTime); mCoundowntimerBtn.setText(formattedTime); } } @Override public void onFinish() { } }; timer.start();
formatRemainingTimeToHHMMSS() is my custom method to render text on the button.
Apart from the mentioned things, I used additional shape background for rounded corners, I used the height of button exactly double to the corner radius to achieve exact semi circle shape.
Comment out if you have any queries.
Hope this helps you in some situations.
Cheers,
Sree
No comments:
Post a Comment