简体   繁体   English

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

[英]Prevent custom SurfaceView from drawing on top of other views

I have created a custom SurfaceView which I use to draw shapes, and the user can zoom and pan the view to interact with the shapes. 我创建了一个自定义SurfaceView,用于绘制形状,用户可以缩放和平移视图以与形状进行交互。 This all works great, but the problem now is that the shapes will always be drawn on top of everything on my screen, also on top of other views such as buttons and textviews. 这一切都很有效,但现在的问题是,形状将始终绘制在屏幕上的所有内容上,也可以放在其他视图(如按钮和textview)之上。 I have tried ordering the custom view and my buttons in different ways in the XML layout, tried parenting the views to FrameLayouts and RelativeLayouts ( as suggested here ). 我尝试在XML布局中以不同的方式排序自定义视图和我的按钮,尝试将视图父级化为 FrameLayouts和RelativeLayouts( 如此处所示 )。

I would like to have buttons and other layout elements floating on top of my custom view. 我想将按钮和其他布局元素浮动在我的自定义视图之上。 As seen in the image below, when I pan my view the rectangle will obscure the buttons. 如下图所示,当我平移视图时,矩形会遮挡按钮。

How can I prevent my custom SurfaceView from drawing on top of everything? 如何防止我的自定义SurfaceView在所有内容上绘图?

在此输入图像描述

My drawing code runs in a separate thread in the SurfaceView class: 我的绘图代码在SurfaceView类的一个单独的线程中运行:

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);
            }
        }       
    }
}
}

My test XML layout, which I would expect to create a button (Left) which is behind the custom view and a button (Right) which is floating above the custom view, is: 我的测试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>

In my code I was calling the function setZOrderOnTop(true); 在我的代码中,我调用了函数setZOrderOnTop(true); which made sure that the surface view would always be drawn on top of everything. 这确保了表面视图总是被绘制在一切之上。 This piece of code was left in by the previous developer in order to have a custom background for the canvas instead of only a solid color. 这段代码由前一个开发人员保留,以便为画布提供自定义背景,而不是仅使用纯色。 With SurfaceView it is a tradeoff between having a custom background for the canvas or being able to draw views on top of the canvas. 使用SurfaceView,可以在为画布设置自定义背景或在画布顶部绘制视图之间进行权衡。

The options are 选项是

  1. With setZOrderOnTop(true); 使用setZOrderOnTop(true); there can be custom backgrounds but no overlaying views. 可以有自定义背景但没有重叠视图。
  2. With setZOrderOnTop(false); setZOrderOnTop(false); there can be overlaying views but only solid color backgrounds for the canvas (by calling eg canvas.drawColor(Color.WHITE); to clear between draw calls). 可以有覆盖视图但只有画布的纯色背景(通过调用例如canvas.drawColor(Color.WHITE);在绘制调用之间清除)。

I chose the second option as I value overlaying views over custom backgrounds. 我选择了第二个选项,因为我重视在自定义背景上覆盖视图。

I'm facing a similar issue. 我面临着类似的问题。 I want to put transparent SurfaceView between another views which are being animated in RelativeLayout . 我想将透明SurfaceView放在另一个在RelativeLayout中动画的视图之间。 When I do so, during animation views sometimes dissapear, sometimes only part of them is visible, it is weird. 当我这样做时,在动画视图中有时会消失,有时只有部分可见,这很奇怪。 Then I discovered if I put SurfaceView to the layout first (so at the bottom) and then I call SurfaceView.setZOrderMediaOverlay(true) , the content of SurfaceView is drawn at the bottom of the window, view are drawn on the top. 然后我发现如果我首先将SurfaceView放到布局中(所以在底部),然后我调用SurfaceView.setZOrderMediaOverlay(true)SurfaceView的内容绘制在窗口的底部,视图绘制在顶部。 If I put SurfaceView anywhere in the layout and then call SurfaceView.setZOrderOnTop(true) , the content is always drawn on the top of the window (and also on the top of the views). 如果我将SurfaceView放在布局中的任何位置,然后调用SurfaceView.setZOrderOnTop(true) ,则内容始终绘制在窗口的顶部(也位于视图的顶部)。 If I put SurfaceView between views, its behavior is crazy, maybe it's because content of SurfaceView is drawn from separated thread and views are drawn from GUI (main) thread so they are "fighting" and that's why this behavior. 如果我将SurfaceView放在视图之间,它的行为是疯狂的,也许是因为SurfaceView的内容是从分离的线程中提取的,而视图是从GUI(主)线程中提取出来的,所以它们是“战斗”,这就是为什么这种行为。 Only way I found is drawing at the bottom or at the top. 我发现的唯一方法是在底部或顶部绘制。 Try to create a new Fragment with transparent background where the SurfaceView is at the bottom as I described in first case and put that buttons you want to have above on top of it (so add them later in some RelativeLayout or FrameLayout ) then show this fragment on the top of activity which holds content you want to have below it. 尝试创建一个具有透明背景的新Fragment ,其中SurfaceView位于底部,如我在第一种情况下所描述的那样,并将您想要的上面的按钮放在它上面(所以稍后在一些RelativeLayoutFrameLayout添加它们)然后显示此片段在活动的顶部,包含您想要在其下面的内容。 Hopefully I helped a bit. 希望我帮了一下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM