防止自定义 SurfaceView 在其他视图之上绘制

Prevent custom SurfaceView from drawing on top of other views

我创建了一个用于绘制形状的自定义 SurfaceView,用户可以缩放和平移视图以与形状进行交互。这一切都很好,但现在的问题是形状将始终绘制在屏幕上的 everything 之上,也会绘制在其他视图(如按钮和文本视图)之上。我已经尝试在 XML 布局中以不同方式对自定义视图和我的按钮进行排序,尝试将视图作为 FrameLayouts 和 RelativeLayouts (as suggested here) 的父级。

我想让按钮和其他布局元素浮动在我的自定义视图之上。如下图所示,当我平移视图时,矩形会遮住按钮。

如何防止我的自定义 SurfaceView 在所有内容之上绘制?

我的绘图代码在 SurfaceView 的单独线程中运行 class:

public class CustomShapeView extends SurfaceView implements Runnable, SurfaceHolder.Callback {

/* Other implementation stuff */

@Override
public void run() {
    while (isDrawing) {
        if (!holder.getSurface().isValid())
            continue; //wait till it becomes valid  

        Canvas canvas = null;
        try {
            canvas = holder.lockCanvas(null);
            synchronized (holder) {
                try {
                    lock.lock();                                
                    canvas.concat(sampleMatrix);
                    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                    drawShapes(canvas);                     
                } finally {
                    lock.unlock();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (canvas != null) {
                holder.unlockCanvasAndPost(canvas);
            }
        }       
    }
}
}

我的测试 XML 布局是:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Left"
    android:id="@+id/button"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"/>

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.CustomShapeView
        android:id="@+id/floor_plan_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</FrameLayout>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Right"
        android:id="@+id/button2"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"/>
</RelativeLayout>   
</RelativeLayout>

我遇到了类似的问题。我想在 RelativeLayout 中动画的另一个视图之间放置透明 SurfaceView。当我这样做时,动画视图有时会消失,有时只有一部分可见,这很奇怪。然后我发现如果我先把 SurfaceView 放到布局中(所以在底部)然后我调用 SurfaceView.setZOrderMediaOverlay(true)SurfaceView 的内容被绘制在 [=26= 的底部],视图绘制在顶部。如果我将 SurfaceView 放在布局中的任何位置,然后调用 SurfaceView.setZOrderOnTop(true),内容总是绘制在 window 的顶部(以及视图的顶部)。如果我将 SurfaceView 放在视图之间,它的行为很疯狂,可能是因为 SurfaceView 的内容是从单独的线程中绘制的,而视图是从 GUI(主)线程中绘制的,所以它们是 "fighting" 和这就是为什么会出现这种行为。我发现的唯一方法是在底部或顶部绘图。尝试创建一个具有透明背景的新 Fragment,其中 SurfaceView 位于底部,如我在第一种情况下所描述的那样,并将您想要的按钮放在它上面(因此稍后在一些RelativeLayoutFrameLayout) 然后在 activity 的顶部显示此片段,其中包含您想要在其下方显示的内容。希望我有所帮助。

在我的代码中,我调用了函数 setZOrderOnTop(true);,它确保表面视图始终绘制在所有内容之上。这段代码是以前的开发人员留下的,目的是为 canvas 提供自定义背景,而不仅仅是纯色。使用 SurfaceView,需要在为 canvas 自定义背景或能够在 canvas.

之上绘制视图之间进行权衡

选项是

  1. 使用 setZOrderOnTop(true); 可以有自定义背景但没有叠加视图。
  2. 使用 setZOrderOnTop(false); 可以有叠加视图,但 canvas 只能有纯色背景(通过调用例如 canvas.drawColor(Color.WHITE); 在绘制调用之间清除)。

我选择了第二个选项,因为我重视在自定义背景上叠加视图。