I want semi circle progress bar in background of image. just like below image.
i have tried to draw using canvas but can't get success. i have also tired some custom progress bar library but result is same.
any suggestions.
looking for one time development and used in every screen size.
Step 1: First, we will design a basic progress bar structure using HTML. First, we will create a container div that holds both progress bars. After that, we will create another div inside the container div that creates the circular div element.
Progress bar supports two modes to represent progress: determinate, and indeterminate. For a visual overview of the difference between determinate and indeterminate progress modes, see Progress & activity.
This can be implemented by clipping a canvas containing an image at an angle (By drawing an arc).
You can use an image something like this
And clip that image by drawing an arc.
Here is how you can do it.
//Convert the progress in range of 0 to 100 to angle in range of 0 180. Easy math. float angle = (progress * 180) / 100; mClippingPath.reset(); //Define a rectangle containing the image RectF oval = new RectF(mPivotX, mPivotY, mPivotX + mBitmap.getWidth(), mPivotY + mBitmap.getHeight()); //Move the current position to center of rect mClippingPath.moveTo(oval.centerX(), oval.centerY()); //Draw an arc from center to given angle mClippingPath.addArc(oval, 180, angle); //Draw a line from end of arc to center mClippingPath.lineTo(oval.centerX(), oval.centerY());
And once you get the path, you can use clipPath
function to clip the canvas in that path.
canvas.clipPath(mClippingPath);
Here is the Complete code
SemiCircleProgressBarView.java
import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Path; import android.graphics.RectF; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.View; public class SemiCircleProgressBarView extends View { private Path mClippingPath; private Context mContext; private Bitmap mBitmap; private float mPivotX; private float mPivotY; public SemiCircleProgressBarView(Context context) { super(context); mContext = context; initilizeImage(); } public SemiCircleProgressBarView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; initilizeImage(); } private void initilizeImage() { mClippingPath = new Path(); //Top left coordinates of image. Give appropriate values depending on the position you wnat image to be placed mPivotX = getScreenGridUnit(); mPivotY = 0; //Adjust the image size to support different screen sizes Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.circle); int imageWidth = (int) (getScreenGridUnit() * 30); int imageHeight = (int) (getScreenGridUnit() * 30); mBitmap = Bitmap.createScaledBitmap(bitmap, imageWidth, imageHeight, false); } public void setClipping(float progress) { //Convert the progress in range of 0 to 100 to angle in range of 0 180. Easy math. float angle = (progress * 180) / 100; mClippingPath.reset(); //Define a rectangle containing the image RectF oval = new RectF(mPivotX, mPivotY, mPivotX + mBitmap.getWidth(), mPivotY + mBitmap.getHeight()); //Move the current position to center of rect mClippingPath.moveTo(oval.centerX(), oval.centerY()); //Draw an arc from center to given angle mClippingPath.addArc(oval, 180, angle); //Draw a line from end of arc to center mClippingPath.lineTo(oval.centerX(), oval.centerY()); //Redraw the canvas invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //Clip the canvas canvas.clipPath(mClippingPath); canvas.drawBitmap(mBitmap, mPivotX, mPivotY, null); } private float getScreenGridUnit() { DisplayMetrics metrics = new DisplayMetrics(); ((Activity)mContext).getWindowManager().getDefaultDisplay().getMetrics(metrics); return metrics.widthPixels / 32; } }
And using it in any activity is very easy.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <com.example.progressbardemo.SemiCircleProgressBarView android:id="@+id/progress" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
Note that clipPath
function doesn't work if the hardware acceleration
is turned on. You can turn off the hardware acceleration only for that view.
//Turn off hardware accleration semiCircleProgressBarView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
MainActivity.java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SemiCircleProgressBarView semiCircleProgressBarView = (SemiCircleProgressBarView) findViewById(R.id.progress); semiCircleProgressBarView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); semiCircleProgressBarView.setClipping(70); } }
As and when the progress changes you can set the progressbar by calling function,
semiCircleProgressBarView.setClipping(progress);
Ex: semiCircleProgressBarView.setClipping(50); //50% progress
semiCircleProgressBarView.setClipping(70); //70% progress
You can use your own Image to match the requirements. Hope it helps!!
Edit : To move the semi circle to bottom of the screen, change mPivotY
value. Something like this
//In `SemiCircleProgressBarView.java` //We don't get the canvas width and height initially, set `mPivoyY` inside `onWindowFocusChanged` since `getHeight` returns proper results by that time public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); mPivotX = getScreenGridUnit(); mPivotY = getHeight() - (mBitmap.getHeight() / 2); }
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