Android 大小两个Surface切换 |
您所在的位置:网站首页 › surfaceview不显示 › Android 大小两个Surface切换 |
在视频聊天app中一般会有这样的场景,一个大的Surface显示对方的画面,一个略小的Surface显示自己的画面(类似于微信视频聊天),然后点击一下小的那个Surface,会把两个画面对调。今天就来看看,这个是怎么实现的。 先给大家一个直观的认识,来两张截图。 Note that this must be set before the surface view's containing * window is attached to the window manager. * * Calling this overrides any previous call to {@link #setZOrderOnTop}. */ public void setZOrderMediaOverlay(boolean isMediaOverlay) { mWindowType = isMediaOverlay ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; } Note that this must be set before the surface view’s containing window is attached to the window manager.应该可以看得懂吧。 所以就得想个办法来绕开这个这个限制,最简单的就是先removeView(View)再addView(View)这样就相当于重新做了attach操作,setZOrderMediaOverlay操作也就可以生效了。接下来看看代码具体如何实现 private RelativeLayout.LayoutParams getSmallLayoutParams() { RelativeLayout.LayoutParams lpSmall = null; lpSmall = new RelativeLayout.LayoutParams(mWindowWidth / 2, mWindowHeight / 2); lpSmall.width = mWindowWidth / 2; lpSmall.height = mWindowHeight / 2; lpSmall.topMargin = mWindowHeight / 2; lpSmall.leftMargin = 0; return lpSmall; } private RelativeLayout.LayoutParams getNormalLayoutParams() { RelativeLayout.LayoutParams lpNormal = null; lpNormal = new RelativeLayout.LayoutParams(mWindowWidth / 2, mWindowHeight / 2); lpNormal.width = mWindowWidth; lpNormal.height = mWindowHeight; lpNormal.topMargin = 0; lpNormal.leftMargin = 0; return lpNormal; } private void changeScreen() { mIsChangeScreen = !mIsChangeScreen; RelativeLayout.LayoutParams lpSmall = getSmallLayoutParams(); RelativeLayout.LayoutParams lpNormal = getNormalLayoutParams(); mRlRoot.removeView(mSurfaceViewSmall); mRlRoot.removeView(mSurfaceView); mRlRoot.removeView(mRlFun); if (mIsChangeScreen) { mSurfaceView.setLayoutParams(lpSmall); mRlRoot.addView(mSurfaceView); mSurfaceViewSmall.setLayoutParams(lpNormal); mRlRoot.addView(mSurfaceViewSmall); // mSurfaceView.setZOrderOnTop(true); mSurfaceView.setZOrderMediaOverlay(true); } else { mSurfaceViewSmall.setLayoutParams(lpSmall); mRlRoot.addView(mSurfaceViewSmall); mSurfaceView.setLayoutParams(lpNormal); mRlRoot.addView(mSurfaceView); // mSurfaceViewSmall.setZOrderOnTop(true); mSurfaceViewSmall.setZOrderMediaOverlay(true); } mRlRoot.addView(mRlFun); }点击小画面右上角按钮的时候,调用changeScreen()方法,这个代码其实不难理解,先removeView调大小两个Surface,修改LayoutParams后一次addView进去,然后通过调用setZOrderMediaOverlay方法修改层级关系,就实现了大小和层级的切换。 这里还有一个mRlRoot.removeView(mRlFun);和mRlRoot.addView(mRlFun);其实是把其他控件的移除和加入操作,目的是防止Surface把其他控件覆盖调。 ####tips: setZOrderOnTop&setZOrderMediaOverlay 这里再简单讲解下这两个方法的区别,我再网上查到很多关于多个Surface重叠显示,放置遮盖其他控件的解决方法,都是说先调用setZOrderOnTop(true)方法,再调用setZOrderMediaOverlay(true),先不评价这个方法的正确性(因为这样确实可以达到目的),我们先看看这两个方法的含义。 setZOrderMediaOverlay方法的源码注释我已经在前面有贴,意思就是"把目标Surface显示在其他Surface之前,如果以前有其他控件覆盖,任然会覆盖在它上面" 然后setZOrderOnTop方法, /** * Control whether the surface view's surface is placed on top of its * window. Normally it is placed behind the window, to allow it to * (for the most part) appear to composite with the views in the * hierarchy. By setting this, you cause it to be placed above the * window. This means that none of the contents of the window this * SurfaceView is in will be visible on top of its surface. * *Note that this must be set before the surface view's containing * window is attached to the window manager. * * Calling this overrides any previous call to {@link #setZOrderMediaOverlay}. */ public void setZOrderOnTop(boolean onTop) { if (onTop) { mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; // ensures the surface is placed below the IME mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } else { mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } } 这个方法的意思就是“调用之后,会把目标Surface显示到window的最前面,包括其他控件” 意思已经很明显了 ,我们在Surface上要显示一下其他控件,比如小画面右上角的按钮,所以调用setZOrderMediaOverlay(true)是最好的,进过试验,只调用setZOrderMediaOverlay(true)就可以达到想要的结果。 所以我就不太理解,为什么那么多博文要说同时调用两个方法呢。总结下自己的经验,希望对大家有所帮助。 最近研究了一下,只需要setZOrderMediaOverlay,来切换SurfaceView的层级关系。不过需要注意的是: 1.上层的SurfaceView需要调用setZOrderMediaOverlay(true),底层的SurfaceView需要调用setZOrderMediaOverlay(false) 2.需要切换的两个SurfaceView必须要有大小变化 3.自测安卓8 9 10版本都是可以的,但是安卓6会有问题 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |