UnityAndroid(4) Unity上显示窗口

发现一般的UI界面都是显示在Unity界面的后面的,即Unity控件的zOrder是最高的。

用于WebRtc显示的SurfaceViewRender在视频(本地或者远程)出来后是能显示到Unity上面的,但是视频还没有出来时,等待时,是被Unity遮挡着的。

查到一个资料:https://android.jlelse.eu/unity-and-android-connecting-the-dots-6368b31e86c5,这个网页在家里电脑居然显示不了,公司电脑可以(有科学上网)。

英文的,他们是要在unity上面显示其他东西。

这个效果是我需要的。

调试过程中需要查看程序界面结构,记得AndroidStudio支持的。以前是用DeviceMonitor(参考:Android studio 查看页面布局层次结构工具使用教程),现在(AndroidStudio3.5.2)有新的工具(参考:AndroidStudio3.0以上替代DDMS的hierarchyviewer工具查看布局层级)。

从上面的资料以及LayoutInspector来看,UnityPlayer里面确实只有一个SurfaceView。

资料的内容总之就是

1.UnityPlayer里面设置了ZOrder,setZOrderOnTop,所有是显示在最前面的。

public UnityPlayer(ContextWrapper contextWrapper) {
    super(contextWrapper);
    ...
    this.mSurfaceView = new SurfaceView((Context)contextWrapper);
    this.mSurfaceView.getHolder().setFormat(2);
    ...
    this.mSurfaceView.setFocusable(true);
    this.mSurfaceView.setFocusableInTouchMode(true);
    // added on Unity 5.6 
    // removed in patch 5.6.1p4
    this.mSurfaceView.setZOrderOnTop(true);
    addView(mSurfaceView);
}

我看到的代码是这样的:

private SurfaceView c() {
        SurfaceView var1 = new SurfaceView(this.t);
        if (b()) {
            var1.getHolder().setFormat(-3);
            var1.setZOrderOnTop(true);
        } else {
            var1.getHolder().setFormat(-1);
        }

        var1.getHolder().addCallback(new Callback() {
            ....
        });
        var1.setFocusable(true);
        var1.setFocusableInTouchMode(true);
        return var1;
    }

想起来js代码格式化后的,这也是格式化了的,c是什么b是什么t是什么....

想着是不是能够写一个MyUnityPlayer继承或者复制UnityPlayer的内容后修改。继承的话没有找到相关的可修改的接口,复制的话,看不懂,而且语法上过不去。不像以前干过的还原awrtc.js的过程,至少它的语法是没问题的,慢慢里面内容修改名称就好了。

2.可以通过修改SurfaceView的ZOrder的方式来处理,但是会有副作用,黑屏一下。

不知道他的具体代码是怎样的,我的要么Unity部分直接就是变黑了,要么Acitivity退出了。根据在不同地方调用下面的代码。

    private void setSurfaceViewZ(){
        SurfaceView unitySurfaceView=(SurfaceView)mUnityPlayer.getChildAt(0);
        mUnityPlayer.removeView(unitySurfaceView);
        unitySurfaceView.setZOrderOnTop(false);
        mUnityPlayer.addView(unitySurfaceView);
        //mUnityPlayer.resume();
    }

在AS里面查看UnityPlayer的代码,发现是处理过的。

3.可以通过创建并显示一个透明的PopupWindow的方式,实现在Unity上面显示窗口的效果。

把资料里面代码直接拷贝过来会发现,缺少setPopUpWindowLayoutType。

这个TYPE_APPLICATION_SUB_PANEL是核心:

总之就是PopupWindow的默认属性是TYPE_APPLICATION_PANEL,要改成TYPE_APPLICATION_SUB_PANEL,Unity的默认也是TYPE_APPLICATION_PANEL。TYPE_APPLICATION_SUB_PANEL会显示在TYPE_APPLICATION_PANEL的前面。

百度上找不到什么setPopUpWindowLayoutType()的有用的信息,goolge上能够搜索到github里面的代码,其实像这样找不到代码时直接在github上找,一般能找到相关的线索。

参考1:https://github.com/mobfox/SDK-Plugins/blob/master/Unity/MobFox-Android-Unity-Plugin/app/src/main/java/com/mobfox/unity/plugin/MobFoxPlugin.java

参考2:https://github.com/koljanich/AdmobUnity/blob/master/source/android-library/app/src/main/java/com/google/unity/ads/NativeExpressAd.java

这两个都是UnityAndroid相关的项目,有空再研究研究。先把需要的代码拿出来,参考1里的

    public static void setPopUpWindowLayoutType(PopupWindow popupWindow, int layoutType) {
        try {
            Method method = PopupWindow.class.getDeclaredMethod("setWindowLayoutType", int.class);
            method.setAccessible(true);
            method.invoke(popupWindow, layoutType);
        } catch (NoSuchMethodException exception) {
            Log.w(TAG, String.format("Unable to set popUpWindow window layout type: %s",
                    exception.getLocalizedMessage()));
        } catch (IllegalAccessException exception) {
            Log.w(TAG, String.format("Unable to set popUpWindow window layout type: %s",
                    exception.getLocalizedMessage()));
        } catch (InvocationTargetException exception) {
            Log.d(TAG, String.format("Unable to set popUpWindow window layout type: %s",
                    exception.getLocalizedMessage()));
        }
    }

感觉是用反射的方式修改属性,大概没有直接开放接口吧。(是不是也能继承UnityPlayer并用反射的方式修改abcd呢...)

两个代码都加入项目中,(点击按钮)创建PopupWindow,看不到效果,因为是透明的,relativeLayout弄个背景色,就能看到一个挡住全部区域的界面,包括Unity也被挡住了。

把要显示的SurfaceViewRender放到里面,可以显示。但是问题是挡住了,也就意味着无法触发Unity的事件了。我最开始不打算用Dialog也是因为这个问题。

换个思路,修改PopupWindow的大小,不全屏,拖动PopupWindow就好了。

参考:5分钟搞定PopUpWindowAndroid Popupwindow 拖动

过程就不写了,总之这个思路可以,最后得到个UnityPopupWinodw的类。

-----------------------------------------------------------------------------------------------------------

经过测试,公司的大部分手机(Android9,Android10)都得到预期的效果了,但是碰到一个Android7的手机,发现很奇怪的情况。

我的实际项目应用是显示远程摄像机的监控视频,用WebRtc,参考:视频服务器(11) Kurento[6] Android播放

1.SurfaceView在PopupWindow中会形成显示不出来,同时形成一个洞,可以看到Window后面的界面。

界面:

运行后,这两个地方就“开洞”了:

2.SurfaceViewRenderer(本质是SurfaceView)在视频播放后,不会自动显示到Unity层上面,还是被Unity挡住了。

第一种情况,没办法,考虑放弃用PopupWIndow。

第二种情况,就是图层的问题了,还是ZOrder。

继续重新看一遍前面的资料,https://android.jlelse.eu/unity-and-android-connecting-the-dots-6368b31e86c5

疑惑1:到底有没有setZOrderOnTop?

正好前面接触了一下java的反射,而我的C#知识告诉我可以用这种方式访问private的方法的。

所以用反射的方式在合适的地方,调用b(),看一下结果。

Method method = UnityPlayer.class.getDeclaredMethod("b");
method.setAccessible(true);
Object result=method.invoke(null);

结果是false。

看来一下UnityPlayer的构造函数

UnityPlayer本身就是一个FrameLayout里面加一个SurfaceView,所有的三维内容都是绘制在SurfaceView里面的。

所以方案就是将显示视频的SurfaceViewRender也放到这个FrameLayout并显示在Unity的SurfaceView的上面。

----------------------------------------------------------

视频界面显示出来了,还有个问题是,位置不正确。设置为(0,0)的时候看不到,用Tools->Layout Inspector查看了一下,方向位置偏到手机屏幕的上方去了,比如(0,-1433)的位置。

发现有两种情况,UnityPlayer也是放在一个LinearLayout里面显示的,SurfaceViewRender假如这个LinnerLayout的layout_height是match_parent,则会有这个问题,加入layout_height是一个具体高度,比如500dp,则没有这个问题,设置(0,0)的情况下,就是在左上角。

手机横屏竖屏旋转时也有这个问题,在一个角度下正常显示的界面,到另一个角度就不见了。

考虑和获取控件宽度的问题一样,需要在重新布局后再去获取宽度,设置位置。

结论上讲就是在初始化UnityPlayer的地方添加addOnGlobalLayoutListener,在里面修改位置信息,需要修改的目标坐标已经保存变量里了。

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值