安卓 : Semi Circle Progress Bar

标签 android progress-bar android-progressbar

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

enter image description here

我曾尝试使用 Canvas 进行绘制,但未能成功。我也厌倦了一些自定义进度条库,但结果是一样的。

任何建议。

寻求一次性开发并用于各种屏幕尺寸。

最佳答案

这可以通过以一定角度剪切包含图像的 Canvas 来实现(通过绘制弧线)。

您可以使用类似这样的图像

enter image description here

并通过绘制弧线来剪辑该图像。

你可以这样做。

//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());

一旦获得路径,就可以使用 clipPath 函数在该路径中剪辑 Canvas 。

canvas.clipPath(mClippingPath);

这是完整的代码

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;
    }

}

在任何 Activity 中使用它都非常容易。

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>   

请注意,如果硬件加速开启,clipPath功能将不起作用。您只能为该 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);
    }

}  

当进度发生变化时,您可以通过调用函数来设置进度条,

semiCircleProgressBarView.setClipping(progress);

例如:semiCircleProgressBarView.setClipping(50);//50% 进度

enter image description here

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

enter image description here

您可以使用自己的图片来匹配要求。希望对你有帮助!!

编辑:要将半圆移动到屏幕底部,请更改 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);
        }

关于安卓 : Semi Circle Progress Bar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22499964/

相关文章:

python - 进度条动画在 cygwin 中不显示,在 cmd 中正常

c - 如何在 win 32 中使用线程概念实现进度条(显示进度)?

android - 可以隐藏水平样式的进度文本,不确定的 ProgressDialog?

Android : inflate() ignoring utilizing root layout width/height defined in style sheets. 二进制 XML 错误

java - 从 webview 打开原生 map

javascript - 自定义形状进度条

android - 进度对话框在 Activity 恢复时永远旋转

Android ProgressBar 不更新 onProgress

java - Android Studio - 当 TextView 位于自定义 xml 文件时尝试使用代码更改 TextView 属性时,应用程序崩溃

java - 如何将 EditText 中的值添加到自定义 ListView?