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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:04:55  来源:igfitidea点击:

Android : Semi Circle Progress Bar

androidprogress-barandroid-progressbar

提问by Dhaval Parmar

I want semi circle progress bar in background of image. just like below image.

我想要图像背景中的半圆形进度条。就像下图一样。

enter image description here

在此处输入图片说明

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

你可以使用这样的图像

enter image description here

在此处输入图片说明

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 clipPathfunction 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 clipPathfunction doesn't work if the hardware accelerationis 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

enter image description here

在此处输入图片说明

semiCircleProgressBarView.setClipping(70); //70% progress

enter image description here

在此处输入图片说明

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 mPivotYvalue. 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:

现在我的应用程序上的自定义实现看起来有点像这样:

Custom progressbar in CleanMaster

CleanMaster 中的自定义进度条

img src: CleanMaster at Google Play

img src:Google Play 的 CleanMaster

回答by Rohit Arya

You can also use native ProgressBarto achieve semi circle. Define ProgressBarlike 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>

useLevelis falseby default in API Level 21.

useLevelfalse默认情况下,API等级21。

Now since we have set max = 200, to achieve semi circle, range of the progress should be 0to 100. You can play around with these values to achieve desired shape.

现在既然我们已经设置max = 200,实现半圈,进度范围应0100。您可以使用这些值来获得所需的形状。

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'

enter image description here

在此处输入图片说明

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"/>

enter image description here

在此处输入图片说明

<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 :

有关更多信息,请参阅以下网站:

https://github.com/lzyzsd/CircleProgress

https://github.com/lzyzsd/CircleProgress

回答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:

更多选项

  1. The Holo Seekbar library
  2. Tutorial showing semi-circular seekbar link to tutorial
  1. Holo Seekbar 图书馆
  2. 显示半圆形搜索栏链接到教程的教程