Android 用画布清除特定圆外的区域

Android 用画布清除特定圆外的区域,android,canvas,view,porter-duff,Android,Canvas,View,Porter Duff,我有一个自定义视图,它通过填充一个圆圈来显示进度,但现在我正在寻找一种方法来删除此白色圆圈外的视图区域: 这里是我的代码: public class CircleGauge extends View { private int value = 75; private Paint backgroundPaint, gaugePaint, textPaint, circlePaint; ... constructors private void init() {

我有一个自定义视图,它通过填充一个圆圈来显示进度,但现在我正在寻找一种方法来删除此白色圆圈外的视图区域:

这里是我的代码:

public class CircleGauge extends View {
    private int value = 75;
    private Paint backgroundPaint, gaugePaint, textPaint, circlePaint;

    ... constructors 

    private void init() {
        DisplayMetrics metrics = getResources().getDisplayMetrics();

        backgroundPaint = new Paint();
        backgroundPaint.setColor(ResourcesCompat.getColor(getResources(), R.color.favorite_position_gauge_background, null));
        backgroundPaint.setStyle(Paint.Style.FILL);
        backgroundPaint.setAntiAlias(true);

        gaugePaint = new Paint();
        gaugePaint.setColor(ResourcesCompat.getColor(getResources(), R.color.favorite_position_gauge, null));
        gaugePaint.setAntiAlias(true);

        circlePaint = new Paint();
        circlePaint.setColor(Color.WHITE);
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, metrics));
        circlePaint.setAntiAlias(true);

        textPaint = new Paint();
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setColor(Color.WHITE);
        textPaint.setFakeBoldText(true);
        textPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 23, metrics));
        textPaint.setAntiAlias(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), backgroundPaint);
        canvas.drawRect(0, ((float) (100 - value) / 100F) * canvas.getHeight(), canvas.getWidth(), canvas.getHeight(), gaugePaint);
        canvas.drawText(getContext().getString(R.string.percent_value, value), getWidth() / 2, getHeight() * .6F, textPaint);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, (getHeight() / 2) - circlePaint.getStrokeWidth() / 2, circlePaint);
    }

    public void setValue(int value) {
        this.value = value;
        invalidate();
    }
}
我很确定我可以用它来做这件事,但我不知道如何做。

已经为您提供了所需的一切,而无需求助于子类化视图和重写onDraw

首先,让我们从可绘制资源开始。我们想要一个有一种颜色的圆覆盖另一种颜色的圆。为此,我们使用一个LayerDrawable,它是用XML指定的

每个可绘制对象都有一个级别值。您可以通过在可绘图面板上调用setLevel来调整标高0-10000。我们希望使用级别来控制较亮圆的外观。为此,我们将使用一个ClipDrawable,它是用XML定义的

对于圆本身,我们可以使用ShapedRawales。下面是当我们把它们放在一起时的样子:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/field" android:gravity="fill">
        <shape android:shape="oval">
            <stroke android:width="2dp" android:color="@android:color/white"/>
            <solid android:color="#FF78606D"/>
        </shape>
    </item>

    <item android:id="@+id/progress" android:gravity="fill">
        <clip android:gravity="bottom" android:clipOrientation="vertical">
            <shape android:shape="oval" >
                <stroke android:width="2dp" android:color="@android:color/white"/>
                <solid android:color="#FFAB9BA6"/>
            </shape>
        </clip>
    </item>

</layer-list>
public class MainActivity extends AppCompatActivity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.text);
        setLevel(0);
        new AsyncTask<Void, Integer, Void>() {
            @Override
            protected Void doInBackground(Void... params) {

                try {
                    for (int i = 0; i <= 100; i++) {
                        publishProgress(i);
                        Thread.sleep(100);
                    }
                } catch (InterruptedException e) {
                    // just leave
                }

                return null;
            };

            @Override
            protected void onProgressUpdate(Integer... values) {
                setLevel(values[0]);
            }
        }.execute();

    }

    private void setLevel(int level) {

        mTextView.setText(Integer.toString(level) + "%");
        LayerDrawable layerDrawable = (LayerDrawable) mTextView.getBackground();
        Drawable progress = layerDrawable.findDrawableByLayerId(R.id.progress);
        progress.setLevel(level * 100); // drawable levels go 0-10000
    }

}

谢谢,它很好用,很优雅。我不知道setLevel方法
public class MainActivity extends AppCompatActivity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.text);
        setLevel(0);
        new AsyncTask<Void, Integer, Void>() {
            @Override
            protected Void doInBackground(Void... params) {

                try {
                    for (int i = 0; i <= 100; i++) {
                        publishProgress(i);
                        Thread.sleep(100);
                    }
                } catch (InterruptedException e) {
                    // just leave
                }

                return null;
            };

            @Override
            protected void onProgressUpdate(Integer... values) {
                setLevel(values[0]);
            }
        }.execute();

    }

    private void setLevel(int level) {

        mTextView.setText(Integer.toString(level) + "%");
        LayerDrawable layerDrawable = (LayerDrawable) mTextView.getBackground();
        Drawable progress = layerDrawable.findDrawableByLayerId(R.id.progress);
        progress.setLevel(level * 100); // drawable levels go 0-10000
    }

}