Android : 半圆形进度条
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22499964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android : Semi Circle Progress Bar
提问by Dhaval Parmar
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.
寻找一次性开发并用于各种屏幕尺寸。
回答by Abhishek V
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.
获得路径后,您可以使用clipPath
函数在该路径中剪切画布。
canvas.clipPath(mClippingPath);
Here is the Complete code
这是完整的代码
SemiCircleProgressBarView.java
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
活动_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.
请注意,clipPath
如果hardware acceleration
打开该功能,则该功能不起作用。您可以仅为该视图关闭硬件加速。
//Turn off hardware accleration
semiCircleProgressBarView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
MainActivity.java
主活动.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(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
编辑:要将半圆移动到屏幕底部,请更改mPivotY
值。像这样的东西
//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);
}
回答by saran
You can try SeekArc Library. I know its a different kind of seekbar, but with some minor customization, you can use it for your app as a progressbar. I've done the same. You just need to change some properties like seekarc:touchInside="false"
.
Its fairly simple.
你可以试试SeekArc 库。我知道它是一种不同的搜索栏,但是通过一些小的自定义,您可以将它用作您的应用程序的进度条。我也做过同样的事。您只需要更改一些属性,例如seekarc:touchInside="false"
.
它相当简单。
Now the custom implementation on my app looks somewhat like this:
现在我的应用程序上的自定义实现看起来有点像这样:
img src: CleanMaster at Google Play
img src:Google Play 的 CleanMaster
回答by Rohit Arya
You can also use native ProgressBar
to achieve semi circle.
Define ProgressBar
like this:
您也可以使用 nativeProgressBar
来实现半圆。ProgressBar
像这样定义:
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:max="200"
android:progress="0"
android:progressDrawable="@drawable/circular" />
Create drawable:
创建可绘制:
circular
(API Level < 21):
circular
(API 级别 < 21):
<shape
android:innerRadiusRatio="2.3"
android:shape="ring"
android:thickness="5sp" >
<solid android:color="@color/someColor" />
</shape>
circular
(API Level >= 21):
circular
(API 级别 >= 21):
<shape
android:useLevel="true"
android:innerRadiusRatio="2.3"
android:shape="ring"
android:thickness="5sp" >
<solid android:color="@color/someColor" />
</shape>
useLevel
is false
by default in API Level 21.
useLevel
是false
默认情况下,API等级21。
Now since we have set max = 200
, to achieve semi circle, range of the progress should be 0
to 100
. You can play around with these values to achieve desired shape.
现在既然我们已经设置max = 200
,实现半圈,进度范围应0
到100
。您可以使用这些值来获得所需的形状。
Thus use it like this:
因此像这样使用它:
ProgressBar progressBar = (Progressbar) view.findViewById(R.id.progressBar);
progressBar.setProgress(value); // 0 <= value <= 100
回答by Masoud Siahkali
You can use this library :
你可以使用这个库:
compile 'com.github.lzyzsd:circleprogress:1.1.1'
for example :
例如 :
<com.github.lzyzsd.circleprogress.DonutProgress
android:layout_marginLeft="50dp"
android:id="@+id/donut_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:donut_progress="30"/>
<com.github.lzyzsd.circleprogress.ArcProgress
android:id="@+id/arc_progress"
android:background="#214193"
android:layout_marginLeft="50dp"
android:layout_width="100dp"
android:layout_height="100dp"
custom:arc_progress="55"
custom:arc_bottom_text="MEMORY"/>
For more information see the following website :
有关更多信息,请参阅以下网站:
回答by SceLus
This is a view which has height equal to half its width. Use the setters to adjust the behaviour as desired. By default the progress is 0 and the width of the arc is 20. Calling setProgress() will invalidate the view with the progress given. Adding a background drawable is possible and the progress bar will be draw on top.
这是一个高度等于其宽度一半的视图。使用 setter 根据需要调整行为。默认情况下,进度为 0,弧的宽度为 20。调用 setProgress() 将使具有给定进度的视图无效。添加背景可绘制是可能的,进度条将绘制在顶部。
public class SemicircularProgressBar extends View {
private int mProgress;
private RectF mOval;
private RectF mOvalInner;
private Paint mPaintProgress;
private Paint mPaintClip;
private float ovalsDiff;
private Path clipPath;
public SemicircularProgressBar(Context context) {
super(context);
init();
}
public SemicircularProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SemicircularProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mProgress = 0;
ovalsDiff = 20;
mOval = new RectF();
mOvalInner = new RectF();
clipPath = new Path();
mPaintProgress = new Paint();
mPaintProgress.setColor(Color.GREEN);
mPaintProgress.setAntiAlias(true);
mPaintClip = new Paint();
mPaintClip.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaintClip.setAlpha(0);
mPaintClip.setAntiAlias(true);
}
// call this from the code to change the progress displayed
public void setProgress(int progress) {
this.mProgress = progress;
invalidate();
}
// sets the width of the progress arc
public void setProgressBarWidth(float width) {
this.ovalsDiff = width;
invalidate();
}
// sets the color of the bar (#FF00FF00 - Green by default)
public void setProgressBarColor(int color){
this.mPaintProgress.setColor(color);
}
@Override
public void onDraw(Canvas c) {
super.onDraw(c);
mOval.set(0, 0, this.getWidth(), this.getHeight()*2);
mOvalInner.set(0+ovalsDiff, 0+ovalsDiff, this.getWidth()-ovalsDiff, this.getHeight()*2);
clipPath.addArc(mOvalInner, 180, 180);
c.clipPath(clipPath, Op.DIFFERENCE);
c.drawArc(mOval, 180, 180f * ((float) mProgress / 100), true, mPaintProgress);
}
// Setting the view to be always a rectangle with height equal to half of its width
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
ViewGroup.LayoutParams params = this.getLayoutParams();
params.width = parentWidth;
params.height = parentWidth/2;
this.setLayoutParams(params);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
回答by user1406716
You may be able to use this github library - circularseekbar. To achieve the half circle, you will need to manipulate the following attributes: "app:start_angle" & "app:end_angle"
您可以使用这个github 库 - circleseekbar。要实现半圆,您需要操作以下属性:“app:start_angle”和“app:end_angle”
More Options:
更多选项:
- The Holo Seekbar library
- Tutorial showing semi-circular seekbar link to tutorial
- Holo Seekbar 图书馆
- 显示半圆形搜索栏链接到教程的教程