防止自定义 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
位于底部,如我在第一种情况下所描述的那样,并将您想要的按钮放在它上面(因此稍后在一些RelativeLayout
或 FrameLayout
) 然后在 activity 的顶部显示此片段,其中包含您想要在其下方显示的内容。希望我有所帮助。
在我的代码中,我调用了函数 setZOrderOnTop(true);
,它确保表面视图始终绘制在所有内容之上。这段代码是以前的开发人员留下的,目的是为 canvas 提供自定义背景,而不仅仅是纯色。使用 SurfaceView,需要在为 canvas 自定义背景或能够在 canvas.
之上绘制视图之间进行权衡
选项是
- 使用
setZOrderOnTop(true);
可以有自定义背景但没有叠加视图。
- 使用
setZOrderOnTop(false);
可以有叠加视图,但 canvas 只能有纯色背景(通过调用例如 canvas.drawColor(Color.WHITE);
在绘制调用之间清除)。
我选择了第二个选项,因为我重视在自定义背景上叠加视图。
我创建了一个用于绘制形状的自定义 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
位于底部,如我在第一种情况下所描述的那样,并将您想要的按钮放在它上面(因此稍后在一些RelativeLayout
或 FrameLayout
) 然后在 activity 的顶部显示此片段,其中包含您想要在其下方显示的内容。希望我有所帮助。
在我的代码中,我调用了函数 setZOrderOnTop(true);
,它确保表面视图始终绘制在所有内容之上。这段代码是以前的开发人员留下的,目的是为 canvas 提供自定义背景,而不仅仅是纯色。使用 SurfaceView,需要在为 canvas 自定义背景或能够在 canvas.
选项是
- 使用
setZOrderOnTop(true);
可以有自定义背景但没有叠加视图。 - 使用
setZOrderOnTop(false);
可以有叠加视图,但 canvas 只能有纯色背景(通过调用例如canvas.drawColor(Color.WHITE);
在绘制调用之间清除)。
我选择了第二个选项,因为我重视在自定义背景上叠加视图。