用圆形边框View覆盖TextureView

Overlay TextureView with circle border View

Android 新手,但我正在尝试在设备摄像头的 TextureView 流上覆盖一个透明的圆形视图,但是无论我做什么,我都无法让覆盖视图出现在纹理视图。我有这样实现的 TextureView:

package org.tensorflow.demo;

import android.content.Context;
import android.util.AttributeSet;
import android.view.TextureView;

/**
 * A {@link TextureView} that can be adjusted to a specified aspect ratio.
 */
public class AutoFitTextureView extends TextureView {
    private int ratioWidth = 0;
    private int ratioHeight = 0;

    public AutoFitTextureView(final Context context) {
    this(context, null);
  }

    public AutoFitTextureView(final Context context, final AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoFitTextureView(final Context context, final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
     * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
     * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
     *
     * @param width  Relative horizontal size
     * @param height Relative vertical size
     */
    public void setAspectRatio(final int width, final int height) {
        if (width < 0 || height < 0) {
            throw new IllegalArgumentException("Size cannot be negative.");
        }
        ratioWidth = width;
        ratioHeight = height;
        requestLayout();
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int height = MeasureSpec.getSize(heightMeasureSpec);
        if (0 == ratioWidth || 0 == ratioHeight) {
            setMeasuredDimension(width, height);
        } else {
            if (width < height * ratioWidth / ratioHeight) {
                setMeasuredDimension(width, width * ratioHeight / ratioWidth);
            } else {
                setMeasuredDimension(height * ratioWidth / ratioHeight, height);
            }
        }
    }
}

我的叠加层目前看起来像这样(圆圈颜色当前设置为黑色以进行调试:

package org.tensorflow.demo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;


public class OverlayView extends View {
    private final Paint transparentPaint;

    public OverlayView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        transparentPaint = new Paint();
        transparentPaint.setColor(getResources().getColor(android.R.color.black));
    }

    @Override
    public void onDraw(final Canvas canvas) {
        int w = getWidth();
        int h = getHeight();

        int pl = getPaddingLeft();
        int pr = getPaddingRight();
        int pt = getPaddingTop();
        int pb = getPaddingBottom();

        int usableWidth = w - (pl + pr);
        int usableHeight = h - (pt + pb);

        int radius = Math.min(usableWidth, usableHeight) / 2;
        int cx = pl + (usableWidth / 2);
        int cy = pt + (usableHeight / 2);
        canvas.drawCircle(cx, cy, radius, transparentPaint);
    }
}

最后我得到了我的布局xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <org.tensorflow.demo.AutoFitTextureView
        android:id="@+id/texture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <org.tensorflow.demo.OverlayView
        android:id="@+id/overlay"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <org.tensorflow.demo.RecognitionScoreView
        android:id="@+id/results"
        android:layout_width="match_parent"
        android:layout_height="112dp" />

</FrameLayout>

最终使用 PorterDuff.Mode.SRC_OUT 从全屏矩形中切出一个圆来解决此问题:

protected void createWindowFrame() {

    int w = getWidth();
    int h = getHeight();

    windowFrame = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Canvas osCanvas = new Canvas(windowFrame);

    RectF outerRectangle = new RectF(0, 0, getWidth(), getHeight());

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(Color.parseColor("#4885ed"));
    osCanvas.drawRect(outerRectangle, paint);

    paint.setColor(Color.TRANSPARENT);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));

    int pl = getPaddingLeft();
    int pr = getPaddingRight();
    int pt = getPaddingTop();
    int pb = getPaddingBottom();

    int usableWidth = w - (pl + pr);
    int usableHeight = h - (pt + pb);

    int radius = Math.min(usableWidth, usableHeight) / 2;        
    int cx = pl + (usableWidth / 2);
    int cy = pt + (usableHeight / 2);

    osCanvas.drawCircle(cx, cy, radius, paint);
}