Как обрезать круговой путь внутри прямоугольника в Android

Я прочитал более 20 вопросов / ответов, но я все еще не могу получить то, что я хочу. Я хочу вырезать круг внутри прямоугольника, как показано ниже:

Вот мой код:

@Override
protected void onDraw(Canvas canvas) {
    Paint paint = new Paint();
    paint.setStyle(Paint.Style.FILL);
    paint.setARGB(180, 0, 0, 0);
    canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
    Path circularPath = new Path();
    circularPath.addCircle(getWidth() / 2, getHeight() / 2, radius, Path.Direction.CCW);
    canvas.clipPath(circularPath, Region.Op.REPLACE);
    canvas.drawColor(0x00000000);


}

Мой фон (setARGB) отображается правильно, однако ничего не обрезается. Я также пробовал разные Op значения, отличные от REPLACE, принудительная растеризация программного обеспечения (как я читал на некоторых версиях Android clipPath не поддерживает некоторые из Ops) позвонив setLayerType(LAYER_TYPE_SOFTWARE, null); на конструкторе, но безрезультатно. Как мне достичь желаемого эффекта?

Примечание. Моя минимальная версия SDK - 15, поэтому мне не нужно поддерживать что-либо ниже 4.0.

2 ответа

Использование clipPath до drawRect,

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    int width = this.getWidth();
    int height = this.getHeight();

    mPaint.setAntiAlias(true);
    mPaint.setColor(Color.WHITE);
    mPaint.setStyle(Paint.Style.FILL);
    canvas.drawPaint(mPaint);

    float rectWidth = Utils.dpToPx(100.0f);

    Path circularPath = new Path();
    circularPath.addCircle(width / 2.0f, rectWidth / 2.0f, rectWidth / 3.0f, Path.Direction.CCW);
    canvas.clipPath(circularPath, Region.Op.DIFFERENCE);

    mPaint.setColor(Color.BLUE);
    canvas.drawRect((width - rectWidth) / 2.0f, 0.0f, ((width - rectWidth) / 2.0f) + rectWidth, rectWidth, mPaint);
}

Результат

Попробуйте отсечь свой путь в dispatchDraw():

@Override
protected void dispatchDraw(Canvas canvas)
{
    canvas.clipPath(mClipPath, mRegion); // previously created path & region

    super.dispatchDraw(canvas);
}

Удалите код отсечения пути из вашего onDraw метод, и это должно сделать это.

Редактировать:

Создавая свой путь, убедитесь, что вы делаете это только после того, как произошло измерение, например:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    mClipPath.reset();
    float radius = Math.min((float)getMeasuredWidth() / 2f, (float)getMeasuredHeight() / 2f) + 5;
    mClipPath.addCircle((float)getMeasuredWidth() / 2f, (float)getMeasuredHeight() / 2f, radius, Path.Direction.CCW);
}
Другие вопросы по тегам