如何将SurfaceView裁剪成圆形呈现?

4

我想在一个圆形内呈现相机预览,就像这样:

我已经将其工作在添加到活动中的片段内。但是我希望通过将其添加到WindowManager中,在其他应用程序上方显示视图。

所以我已经能够在其他应用程序上方显示视图,但SurfaceView没有剪裁。另外,我已经将SurfaceView剪裁为圆形,但是在片段中。

我已经阅读了许多有关此主题的答案和文章。关于剪切SurfaceView的信息很少,并且没有符合我的要求的库。我找到的大部分信息只是解释如何将其剪裁为正方形或其他矩形。

添加到WindowManager后的效果

我正在尝试绘制

如何剪裁显示在所有视图上方的SurfaceView?

SurfaceView子类

public class CircleSurface extends SurfaceView {

    private Path clipPath;

    public CircleSurface(Context context) {
        super(context);
        init();
    }

    public CircleSurface(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleSurface(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setZOrderMediaOverlay(true);
        setWillNotDraw(false);

        SurfaceHolder sfhTrackHolder = getHolder();
        sfhTrackHolder.setFormat(PixelFormat.TRANSPARENT);


        clipPath = new Path();
        //TODO: define the circle you actually want
        clipPath.addCircle(710, 330, 250, Path.Direction.CW);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.clipPath(clipPath);
        super.dispatchDraw(canvas);
    }
}

为窗口管理器添加视图的服务

public class LiveStreamingService extends Service implements SurfaceHolder.Callback {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(startId, getNotification());
        }
        sharedInstance = this;

        // android shouldn't auto restart this service
        return START_NOT_STICKY;
    }

    @Override
    public void onCreate() {
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

        // camera view
        CircleSurface cameraSurfaceView = new CircleSurface(this);
        cameraSurfaceView.getHolder().addCallback(this);

        wm.addView(cameraSurfaceView, getLayoutParams(360, 270));
    }

    private WindowManager.LayoutParams getLayoutParams(int width, int height) {
        int overlayType = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O 
                ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY 
                : WindowManager.LayoutParams.TYPE_PHONE;

        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                width,
                height,
                overlayType,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                PixelFormat.TRANSLUCENT
        );

        return layoutParams;
    }

    // ...
}

更新

似乎相机的渲染与dispatchDraw方法有所不同。我可以在dispatchDraw中进行任何操作,但相机仍然显示为矩形。


请查看以下内容:https://dev59.com/4Inda4cB1Zd3GeqPCrCQ - ColonD
我尝试了Region.Op.DIFFERENCE和其他标志,但没有任何变化。就像clipPath什么也没做一样。我甚至注释掉了super.dispatchDraw(canvas),但相机仍然显示。 - Troy
1个回答

0

为 SurfaceView 创建了一个绘制线程,监听相机预览回调 - OnPreviewFrame

在线程的绘制循环内:

c.drawColor(0, PorterDuff.Mode.CLEAR);
c.drawColor(0x1000000); // magical color that removes everything (like transparency)

if (currentFrame == null) return;

c.clipPath(circleSurfaceView.path);
c.drawBitmap(currentFrame, 0, 0, paint);

我不知道什么是神奇的颜色。我是偶然发现它的。其他我尝试的一切都只会绘制黑色或模糊噪声。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接