Android: панель прогресса Semi Circle

Я хочу полосу прогресса полукруга в фоновом режиме изображения. как показано ниже.

enter image description here

Я попытался рисовать, используя canvas, но не смог добиться успеха. Я также устал от некоторой пользовательской библиотеки показателей выполнения, но результат такой же.

любые предложения.

ищет одноразовую разработку и используется в каждом размере экрана.

Ответ 1

Это может быть реализовано путем отсечения холста, содержащего изображение под углом (путем рисования дуги).

Вы можете использовать изображение, подобное этому

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.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_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 не работает, если включен hardware acceleration. Вы можете отключить аппаратное ускорение только для этого вида.

   //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% progress

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

Ответ 2

Вы можете попробовать библиотеку SeekArc. Я знаю, что это другой тип поиска, но с небольшой настройкой вы можете использовать его для своего приложения в качестве индикатора прогресса. Я сделал то же самое. Вам просто нужно изменить некоторые свойства, например
seekarc:touchInside="false".
Это довольно просто.

Теперь пользовательская реализация в моем приложении выглядит примерно так:

Custom progressbar in CleanMaster

img src: CleanMaster в Google Play

Ответ 3

Вы также можете использовать native ProgressBar для достижения полукруга. Определите 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" />

Создать drawable:

circular (Уровень API < 21):

<shape
   android:innerRadiusRatio="2.3"
   android:shape="ring"
   android:thickness="5sp" >
   <solid android:color="@color/someColor" />
</shape>

circular (уровень API >= 21):

<shape
   android:useLevel="true"
   android:innerRadiusRatio="2.3"
   android:shape="ring"
   android:thickness="5sp" >
   <solid android:color="@color/someColor" />
</shape>

useLevel по умолчанию используется false в API-интерфейсе уровня 21.

Теперь, когда мы установили max = 200, для достижения полукруга диапазон хода должен быть 0 до 100. Вы можете играть с этими значениями для достижения желаемой формы.

Таким образом, используйте его так:

ProgressBar progressBar = (Progressbar) view.findViewById(R.id.progressBar);
progressBar.setProgress(value); // 0 <= value <= 100

Ответ 4

Это вид, который имеет высоту, равную половине ее ширины. Используйте сеттеры для настройки поведения по желанию. По умолчанию прогресс равен 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);
}
}

Ответ 5

Возможно, вы сможете использовать эту библиотеку github - roundseekbar. Чтобы достичь полукруга, вам нужно будет манипулировать следующими атрибутами: "app: start_angle" и "app: end_angle"

Дополнительные параметры:

Ответ 6

Вы можете использовать эту библиотеку:

 compile 'com.github.lzyzsd:circleprogress:1.1.1'

введите описание изображения здесь

например:

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

Для получения дополнительной информации см. следующий веб-сайт:

https://github.com/lzyzsd/CircleProgress