如何在Android上正确使用setZOrderMediaOverlay?

发布于 2024-11-03 05:48:41 字数 4842 浏览 7 评论 0原文

与许多其他人一样,我尝试在相机预览(使用 SurfaceView)上绘制 3D 对象(使用 GLSurfaceView),以及放置在顶部的一些按钮。我实际上得到了一个可以工作的原型,但是我无法让 onResume 正常工作。恢复后,GLSurfaceView 留在后面并且不再可见。我知道它正在工作,因为如果我从布局中删除 SurfaceView,我可以很好地看到绘图。

目标是 Nexus One,运行原生 2.3.3 ROM。

这是布局 xml: <代码>

<com.example.cameratest.GLPreview 
        android:id="@+id/cubes" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"/> 

<com.example.cameratest.Preview 
        android:id="@+id/camera" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"/> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/buttongroup" 
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_gravity="right" android:gravity="center">

    <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonClose"></Button>
    <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonMode"></Button>    
    <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonCameraInfo"></Button>
</LinearLayout>

<代码>

所有这些都包含在 块中,但由于某种原因,我无法将其包含在上面的 列表中。 Preview 是扩展 SurfaceView 并实现相机预览逻辑的类。

当活动启动时,这效果很好。当我启动另一个活动(例如,按其中一个按钮)并完成该活动后,主活动将恢复,但 3D 对象不再可见。

我发现此讨论其中提到 setZOrderMediaOverlay() 将帮助解决此 z 排序问题。另外,setZOrderMediaOverlay()的Android文档说这个函数应该是称为“在表面视图的包含窗口附加到窗口管理器之前”。我不知道应该如何解释该语句,因此我将调试语句放入代码中以查看事件的顺序。 GLSurfaceView 代码如下所示:


public class GLPreview extends GLSurfaceView
{
    private static final String TAG = "GLPreview";

    public GLPreview(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        // this.setZOrderMediaOverlay(true);        
    }

    public void onPause()
    {
        super.onPause();
        Log.d(TAG, "GLPreview: OnPause");
    }

    public void onResume()
    {
        // this.setZOrderMediaOverlay(true);        
        super.onResume();
        Log.d(TAG, "GLPreview: OnResume");
    }

    public void surfaceCreated(SurfaceHolder holder)
    {
        Log.d(TAG, "GLPreview: surfaceCreated");
        super.surfaceCreated(holder);
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
    {
        Log.d(TAG, String.format("GLPreview: surfaceChanged, format=%d, w=%d, h=%d", format, w, h));
        super.surfaceChanged(holder, format, w, h);
    }

    public void surfaceDestroyed(SurfaceHolder holder)
    {
        Log.d(TAG, "GLPreview: surfaceDestroyed");
        super.surfaceDestroyed(holder);
    }

    protected void onAttachedToWindow()
    {
        Log.d(TAG, "GLPreview: onAttachedToWindow");
        super.onAttachedToWindow();
    }

    protected void onDetachedFromWindow()
    {
        Log.d(TAG, "GLPreview: onDetachedFromWindow");
        super.onDetachedFromWindow();
    }

    protected void onWindowVisibilityChanged (int vis)
    {
        String newVisibility;
        switch (vis)
        {
            case View.GONE:
                newVisibility = "GONE";
                break;
            case View.INVISIBLE:
                newVisibility = "INVISIBLE";
                break;
            case View.VISIBLE:
                newVisibility = "VISIBLE";
                break;
            default:
                newVisibility = String.format("Unknown constant %d", vis);
        }

        Log.d(TAG, String.format("GLPreview: onWindowVisibilityChanged -> %s", newVisibility));
        super.onWindowVisibilityChanged(vis);
    }
}

这是我启动应用程序时的事件顺序:

GLPreview: OnResume
GLPreview: onAttachedToWindow
GLPreview: onWindowVisibilityChanged -> VISIBLE
GLPreview: surfaceCreated
GLPreview: surfaceChanged, format=1, w=800, h=480

因此,我假设需要在 onResume 中调用 setZOrderMediaOverlay() () 或在构造函数中。但是,我在 GLSurfaceView中尝试了 setZOrderMediaOverlay()truefalse 的各种组合>SurfaceView 类,但它们都没有帮助解决问题。

我对 Android 编程还比较陌生。我已经走了这么远,但此时我需要一些帮助。如果有人在这种情况下成功使用了 setZOrderMediaOverlay() 并使其与 onResume() 一起工作,请告诉我需要如何完成此操作。

预先非常感谢!

Like many others, I am trying to draw 3D objects (using GLSurfaceView) on camera preview (using SurfaceView), along with some buttons placed on top. I actually got a prototype working, but I could not get the onResume working correctly. After a resume, GLSurfaceView stays behind and is not visible anymore. I know that it is working, because I can see the drawing fine if I remove the SurfaceView from the layout.

The target is Nexus One, running stock 2.3.3 ROM.

Here's the layout xml:

<com.example.cameratest.GLPreview 
        android:id="@+id/cubes" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"/> 

<com.example.cameratest.Preview 
        android:id="@+id/camera" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"/> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/buttongroup" 
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_gravity="right" android:gravity="center">

    <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonClose"></Button>
    <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonMode"></Button>    
    <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonCameraInfo"></Button>
</LinearLayout>

All of this is wrapped in a <merge> block, but for some reason, I could not include it in the above <code> listing. Preview is the class that extends SurfaceView and implements the camera preview logic.

This works fine when the activity launches. After I launch another activity (for example, by pressing one of the buttons) and finish that activity, the main activity resumes but the 3D objects are not visible anymore.

I found this discussion where it is mentioned that setZOrderMediaOverlay() will help fix this z-ordering issue. Also, the Android document for setZOrderMediaOverlay() says this function should be called "before the surface view's containing window is attached to the window manager". I do not know how I should interpret that statement, so I put debug statements in the code to see the sequence of events. Here's how the GLSurfaceView code looks like:


public class GLPreview extends GLSurfaceView
{
    private static final String TAG = "GLPreview";

    public GLPreview(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        // this.setZOrderMediaOverlay(true);        
    }

    public void onPause()
    {
        super.onPause();
        Log.d(TAG, "GLPreview: OnPause");
    }

    public void onResume()
    {
        // this.setZOrderMediaOverlay(true);        
        super.onResume();
        Log.d(TAG, "GLPreview: OnResume");
    }

    public void surfaceCreated(SurfaceHolder holder)
    {
        Log.d(TAG, "GLPreview: surfaceCreated");
        super.surfaceCreated(holder);
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
    {
        Log.d(TAG, String.format("GLPreview: surfaceChanged, format=%d, w=%d, h=%d", format, w, h));
        super.surfaceChanged(holder, format, w, h);
    }

    public void surfaceDestroyed(SurfaceHolder holder)
    {
        Log.d(TAG, "GLPreview: surfaceDestroyed");
        super.surfaceDestroyed(holder);
    }

    protected void onAttachedToWindow()
    {
        Log.d(TAG, "GLPreview: onAttachedToWindow");
        super.onAttachedToWindow();
    }

    protected void onDetachedFromWindow()
    {
        Log.d(TAG, "GLPreview: onDetachedFromWindow");
        super.onDetachedFromWindow();
    }

    protected void onWindowVisibilityChanged (int vis)
    {
        String newVisibility;
        switch (vis)
        {
            case View.GONE:
                newVisibility = "GONE";
                break;
            case View.INVISIBLE:
                newVisibility = "INVISIBLE";
                break;
            case View.VISIBLE:
                newVisibility = "VISIBLE";
                break;
            default:
                newVisibility = String.format("Unknown constant %d", vis);
        }

        Log.d(TAG, String.format("GLPreview: onWindowVisibilityChanged -> %s", newVisibility));
        super.onWindowVisibilityChanged(vis);
    }
}

Here's the sequence of events when I start the application:

GLPreview: OnResume
GLPreview: onAttachedToWindow
GLPreview: onWindowVisibilityChanged -> VISIBLE
GLPreview: surfaceCreated
GLPreview: surfaceChanged, format=1, w=800, h=480

So I assumed that setZOrderMediaOverlay() needs to be called in either onResume() or in the constructor. However, I tried various combinations of setZOrderMediaOverlay() with true or false, in the GLSurfaceView or the SurfaceView classes, but none of it helped with the problem.

I am relatively new when it comes to Android programming. I have come so far but at this point I need some help. If someone who used setZOrderMediaOverlay() successfully in this scenario and got it working with onResume() let me know how this needs to be done.

Thanks a lot in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

本宫微胖 2024-11-10 05:48:41

我已经为同样的问题苦苦挣扎了一段时间,但相信下面的代码现在可以工作了。 (暂停/锁定后,无论相机打开还是关闭,它都会继续工作)。

首先,我没有在布局文件中定义任何视图等 - 它们是在代码中创建的。以下是从主 onCreate() 方法调用的 - 请注意 augScreen 上的 setZOrderMediaOverlay()。

除了将 onPause() 和 onResume() 传递到 augScreen 之外,我在 onPause() 或 onResume() 中没有做任何特别的事情。

        // 1 - Camera Preview
        camScreen = new CameraPreview(this);
        setContentView(camScreen, new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

    // 2 - 3D object display
        augScreen = new AR_SurfaceView(this, getViewRange());
        addContentView(augScreen, new LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        augScreen.setZOrderMediaOverlay(true);

    // 3 - Permanent overlay
    RelativeLayout overlayScreen = new OverlayView(this);
    addContentView(overlayScreen, new LayoutParams(
            LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    overlayScreen.setVisibility(View.VISIBLE);

    // 4 - UI buttons (toggleable)
        uiScreen = new UserInterfaceView(this);
        addContentView(uiScreen, new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

I have struggled with the same issue for some time, but believe the code below now works. (It continues to work after pausing/ locking regardless of whether the camera is on or off).

Firstly, I haven't got any views etc defined in the layout file - they're created in code. The following is called from the main onCreate() method - Note the setZOrderMediaOverlay() on the augScreen.

I have done nothing special within onPause() or onResume() apart from passing onPause() and onResume() through to the augScreen.

        // 1 - Camera Preview
        camScreen = new CameraPreview(this);
        setContentView(camScreen, new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

    // 2 - 3D object display
        augScreen = new AR_SurfaceView(this, getViewRange());
        addContentView(augScreen, new LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        augScreen.setZOrderMediaOverlay(true);

    // 3 - Permanent overlay
    RelativeLayout overlayScreen = new OverlayView(this);
    addContentView(overlayScreen, new LayoutParams(
            LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    overlayScreen.setVisibility(View.VISIBLE);

    // 4 - UI buttons (toggleable)
        uiScreen = new UserInterfaceView(this);
        addContentView(uiScreen, new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
围归者 2024-11-10 05:48:41

Awila_Tech 的回答也对我有帮助。我使用了 GLSurfaceView 并在 Activity 的 onPause 和 onResume 中巧妙地调用了它的 onPause 和 onResume,但是在调用实际的 onDrawFrame 时,五分之一的屏幕保持黑色。

总结一下:

public class OpenGLApp extends Activity implements GLSurfaceView.Renderer {
    private GLSurfaceView mGLSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGLSurfaceView = new GLSurfaceView(this);
        mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 8);
        mGLSurfaceView.setRenderer(this);
        mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        mGLSurfaceView.setKeepScreenOn(true);
        mGLSurfaceView.setDrawingCacheEnabled(true);
        mGLSurfaceView.setZOrderOnTop(true);

        setContentView(mGLSurfaceView);
        //...
    }

    @Override
    protected void onPause() {
        //...
        mGLSurfaceView.onPause();
        super.onPause();
    }

    @Override
    protected void onResume() {
        mGLSurfaceView.onResume();
        //...
        super.onResume();
    }
}

Awila_Tech's answer helped me as well. I used a GLSurfaceView and neatly called its onPause and onResume in the Activities's onPause and onResume, but 1 out of 5 times my screen stayed black while the actual onDrawFrame was being called.

To summarize:

public class OpenGLApp extends Activity implements GLSurfaceView.Renderer {
    private GLSurfaceView mGLSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGLSurfaceView = new GLSurfaceView(this);
        mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 8);
        mGLSurfaceView.setRenderer(this);
        mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        mGLSurfaceView.setKeepScreenOn(true);
        mGLSurfaceView.setDrawingCacheEnabled(true);
        mGLSurfaceView.setZOrderOnTop(true);

        setContentView(mGLSurfaceView);
        //...
    }

    @Override
    protected void onPause() {
        //...
        mGLSurfaceView.onPause();
        super.onPause();
    }

    @Override
    protected void onResume() {
        mGLSurfaceView.onResume();
        //...
        super.onResume();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文