I'm trying to make a circular progress bar on android and it seems pretty straightforward task , but I'm struggling with rounding the edges of the progress and secondary progress.
Is there a way to do that without making a custom view ? Using a corners radius ? or nine patch drawable ?
For this view (see attachement) I'm using a simple xml file
<item android:id="@android:id/progress"> <shape android:useLevel="true" android:innerRadius="@dimen/sixty_dp" android:shape="ring" android:thickness="@dimen/seven_dp"> <solid android:color="#477C5B"/> <stroke android:width="1dip" android:color="#FFFF"/> </shape> </item>
This example demonstrates how do I make circle custom progress bar in android. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main. xml.
Android 12 introduces Rounded Corner API that enables you to get the properties of a screen's rounded corners, such as its center and its radius. As you can see in the image above, with this API you app can be made aware of the screen's rounded corner and avoid truncating the UI elements.
Sometimes you want an outline around your shape and to do that you can use the stroke tag. You can specify the width and color of the outline using android:width and android:color.
Just create class called MyProgress
in your package .. and paste the following code..
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.text.TextPaint; import android.util.AttributeSet; import android.view.View; public class MyProgress extends View { private Paint mPrimaryPaint; private Paint mSecondaryPaint; private RectF mRectF; private TextPaint mTextPaint; private Paint mBackgroundPaint; private boolean mDrawText = false; private int mSecondaryProgressColor; private int mPrimaryProgressColor; private int mBackgroundColor; private int mStrokeWidth; private int mProgress; private int mSecodaryProgress; private int mTextColor; private int mPrimaryCapSize; private int mSecondaryCapSize; private boolean mIsPrimaryCapVisible; private boolean mIsSecondaryCapVisible; private int x; private int y; private int mWidth = 0, mHeight = 0; public MyProgress(Context context) { super(context); init(context, null); } public MyProgress(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public MyProgress(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } void init(Context context, AttributeSet attrs) { TypedArray a; if (attrs != null) { a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.MyProgress, 0, 0); } else { throw new IllegalArgumentException("Must have to pass the attributes"); } try { mDrawText = a.getBoolean(R.styleable.MyProgress_showProgressText, false); mBackgroundColor = a.getColor(R.styleable.MyProgress_backgroundColor, android.R.color.darker_gray); mPrimaryProgressColor = a.getColor(R.styleable.MyProgress_progressColor, android.R.color.darker_gray); mSecondaryProgressColor = a.getColor(R.styleable.MyProgress_secondaryProgressColor, android.R.color.black); mProgress = a.getInt(R.styleable.MyProgress_progress, 0); mSecodaryProgress = a.getInt(R.styleable.MyProgress_secondaryProgress, 0); mStrokeWidth = a.getDimensionPixelSize(R.styleable.MyProgress_strokeWidth, 20); mTextColor = a.getColor(R.styleable.MyProgress_textColor, android.R.color.black); mPrimaryCapSize = a.getInt(R.styleable.MyProgress_primaryCapSize, 20); mSecondaryCapSize = a.getInt(R.styleable.MyProgress_secodaryCapSize, 20); mIsPrimaryCapVisible = a.getBoolean(R.styleable.MyProgress_primaryCapVisibility, true); mIsSecondaryCapVisible = a.getBoolean(R.styleable.MyProgress_secodaryCapVisibility, true); } finally { a.recycle(); } mBackgroundPaint = new Paint(); mBackgroundPaint.setAntiAlias(true); mBackgroundPaint.setStyle(Paint.Style.STROKE); mBackgroundPaint.setStrokeWidth(mStrokeWidth); mBackgroundPaint.setColor(mBackgroundColor); mPrimaryPaint = new Paint(); mPrimaryPaint.setAntiAlias(true); mPrimaryPaint.setStyle(Paint.Style.STROKE); mPrimaryPaint.setStrokeWidth(mStrokeWidth); mPrimaryPaint.setColor(mPrimaryProgressColor); mSecondaryPaint = new Paint(); mSecondaryPaint.setAntiAlias(true); mSecondaryPaint.setStyle(Paint.Style.STROKE); mSecondaryPaint.setStrokeWidth(mStrokeWidth - 2); mSecondaryPaint.setColor(mSecondaryProgressColor); mTextPaint = new TextPaint(); mTextPaint.setColor(mTextColor); mRectF = new RectF(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mRectF.set(getPaddingLeft(), getPaddingTop(), w - getPaddingRight(), h - getPaddingBottom()); mTextPaint.setTextSize(w / 5); x = (w / 2) - ((int) (mTextPaint.measureText(mProgress + "%") / 2)); y = (int) ((h / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)); mWidth = w; mHeight = h; invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPrimaryPaint.setStyle(Paint.Style.STROKE); mSecondaryPaint.setStyle(Paint.Style.STROKE); // for drawing a full progress .. The background circle canvas.drawArc(mRectF, 0, 360, false, mBackgroundPaint); // for drawing a secondary progress circle int secondarySwipeangle = (mSecodaryProgress * 360) / 100; canvas.drawArc(mRectF, 270, secondarySwipeangle, false, mSecondaryPaint); // for drawing a main progress circle int primarySwipeangle = (mProgress * 360) / 100; canvas.drawArc(mRectF, 270, primarySwipeangle, false, mPrimaryPaint); // for cap of secondary progress int r = (getHeight() - getPaddingLeft() * 2) / 2; // Calculated from canvas width double trad = (secondarySwipeangle - 90) * (Math.PI / 180d); // = 5.1051 int x = (int) (r * Math.cos(trad)); int y = (int) (r * Math.sin(trad)); mSecondaryPaint.setStyle(Paint.Style.FILL); if (mIsSecondaryCapVisible) canvas.drawCircle(x + (mWidth / 2), y + (mHeight / 2), mSecondaryCapSize, mSecondaryPaint); // for cap of primary progress trad = (primarySwipeangle - 90) * (Math.PI / 180d); // = 5.1051 x = (int) (r * Math.cos(trad)); y = (int) (r * Math.sin(trad)); mPrimaryPaint.setStyle(Paint.Style.FILL); if (mIsPrimaryCapVisible) canvas.drawCircle(x + (mWidth / 2), y + (mHeight / 2), mPrimaryCapSize, mPrimaryPaint); if (mDrawText) canvas.drawText(mProgress + "%", x, y, mTextPaint); } public void setDrawText(boolean mDrawText) { this.mDrawText = mDrawText; invalidate(); } public void setBackgroundColor(int mBackgroundColor) { this.mBackgroundColor = mBackgroundColor; invalidate(); } public void setSecondaryProgressColor(int mSecondaryProgressColor) { this.mSecondaryProgressColor = mSecondaryProgressColor; invalidate(); } public void setPrimaryProgressColor(int mPrimaryProgressColor) { this.mPrimaryProgressColor = mPrimaryProgressColor; invalidate(); } public void setStrokeWidth(int mStrokeWidth) { this.mStrokeWidth = mStrokeWidth; invalidate(); } public void setProgress(int mProgress) { this.mProgress = mProgress; invalidate(); } public void setSecondaryProgress(int mSecondaryProgress) { this.mSecodaryProgress = mSecondaryProgress; invalidate(); } public void setTextColor(int mTextColor) { this.mTextColor = mTextColor; invalidate(); } public void setPrimaryCapSize(int mPrimaryCapSize) { this.mPrimaryCapSize = mPrimaryCapSize; invalidate(); } public void setSecondaryCapSize(int mSecondaryCapSize) { this.mSecondaryCapSize = mSecondaryCapSize; invalidate(); } public boolean isPrimaryCapVisible() { return mIsPrimaryCapVisible; } public void setIsPrimaryCapVisible(boolean mIsPrimaryCapVisible) { this.mIsPrimaryCapVisible = mIsPrimaryCapVisible; } public boolean isSecondaryCapVisible() { return mIsSecondaryCapVisible; } public void setIsSecondaryCapVisible(boolean mIsSecondaryCapVisible) { this.mIsSecondaryCapVisible = mIsSecondaryCapVisible; } public int getSecondaryProgressColor() { return mSecondaryProgressColor; } public int getPrimaryProgressColor() { return mPrimaryProgressColor; } public int getProgress() { return mProgress; } public int getBackgroundColor() { return mBackgroundColor; } public int getSecodaryProgress() { return mSecodaryProgress; } public int getPrimaryCapSize() { return mPrimaryCapSize; } public int getSecondaryCapSize() { return mSecondaryCapSize; } }
and add the following line in res->values->attr.xml under a tag and build it
<declare-styleable name="MyProgress"> <attr name="showProgressText" format="boolean" /> <attr name="progress" format="integer" /> <attr name="secondaryProgress" format="integer" /> <attr name="progressColor" format="color" /> <attr name="secondaryProgressColor" format="color" /> <attr name="backgroundColor" format="color" /> <attr name="primaryCapSize" format="integer" /> <attr name="secodaryCapSize" format="integer" /> <attr name="primaryCapVisibility" format="boolean" /> <attr name="secodaryCapVisibility" format="boolean" /> <attr name="strokeWidth" format="dimension" /> <attr name="textColor" format="color" /> </declare-styleable>
that's it .... and to use in your layout ..
<Your_Package_Name.MyProgress android:padding="20dp" android:id="@+id/timer1" app:strokeWidth="10dp" app:progress="30" app:secondaryProgress="50" app:backgroundColor="@android:color/black" app:progressColor="@android:color/holo_blue_bright" app:secondaryProgressColor="@android:color/holo_blue_dark" app:primaryCapSize="30" app:secodaryCapSize="40" app:primaryCapVisibility="true" app:secodaryCapVisibility="true" android:layout_width="200dp" android:layout_height="200dp" />
You can also change all property progrmatically using setMethods()...
feel free to ask anything .. best of luck
[Update 23-01-2016]
finally I uploaded code on github. You can refer it from here https://github.com/msquare097/MProgressBar
Now You can use this ProgressBar by simply writing following line in your app build.gradle file. You don't have to copy above code.
compile 'com.msquare.widget.mprogressbar:mprogressbar:1.0.0'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With