Android小窗口/分屏模式适配

2,371 阅读5分钟

小窗口/分屏模式

首先来看看什么是小窗口模式,如下图:

Screenshot_20240115_154017_com.example.myapplication.jpg   目前使用小窗口模式的可能会比较多,就我个人而言,我也经常使用小窗口模式,真的是方便,不用来回切换两个应用,所以适配方面,还是推荐进行适配的。

判断当前是否处于小窗口模式/分屏模式

// 是否是小屏/分屏模式
public static boolean isInMultiWindowMode(Context context) {
    if (RomUtils.isOppo())
        return isInMultiWindowModeCheckOppo(context);
    else {
        boolean isInMultiWindowMode = false;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (context instanceof Activity) {
                return ((Activity) context).isInMultiWindowMode();
            }
        }
        return false;
    }
}

private static boolean isInMultiWindowModeCheckOppo(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        ///获取App界面宽高
        WindowManager localWindowManager =
                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        WindowMetrics currentWindowMetrics = localWindowManager.getCurrentWindowMetrics();
        int height = currentWindowMetrics.getBounds().height();
        int width = currentWindowMetrics.getBounds().width();
        L.i("app check window width: " + width + " height: " + height);
        ///获取屏幕宽高
        Display display = context.getDisplay();
        if (display != null) {
            int physicalHeight = context.getDisplay().getMode().getPhysicalHeight();
            int physicalWidth = context.getDisplay().getMode().getPhysicalWidth();
            L.i("app check window physicalWidth: " + physicalWidth + " physicalWidth: " + physicalHeight);
            return width != physicalWidth || height != physicalHeight;
        }
    }
    return false;
}

经实测:oppo的小窗口模式还是会返回false,只有分屏模式才会返回true,小米/华为/vivo的小窗口模式/分屏模式均返回true。问了oppo技术支持,oppo这边只能通过判断宽高尺寸来区分出小窗口/分屏模式。

界面适配

  小窗口/分屏模式是系统默认开启支持的,界面来说其实就是类似小屏幕,只是这个小窗口的宽高比要比小屏幕的还要小,所以需要进行适配,不然可能显示不全,或者有哪些逻辑导致崩溃,都是会出现的呢。
  1、首先说下想要禁用的方法:
在AndroidManifest.xml文件中的application节点或者activity节点中添加如下:

android:resizeableActivity="false" // 系统默认为true

  2、开启功能的话,则需要进行适配了,适配区分两种情况:
  2.1、第一种是界面是列表类型的,可以进行上下滚动,切换成小窗口模式也能完全展示出来的,则这种情况可以不用去适配界面;或者界面内容很少,切换成小窗口后所有控件同样能完全展示出来的也可以不用去适配界面。这时候,直接在AndroidManifest.xml的Activity中添加以下属性:

android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"

该属性添加“screenLayout”可以避免在切换小窗口模式和正常模式时,Activity界面重新创建的问题,因为界面能直接复用完全展示,所以也自然无需重新创建重新布局了。
  2.2、第二种是界面是,切换成小窗口模式后,界面显示不完整,并且又不能通过滚动进行查看,这时候就需要对界面进行重新布局以匹配小窗口模式的大小了。在AndroidManifest.xml的Activity中android:configChanges里面不要添加"screenLayout"选项,这时候,切换成小窗口模式,或者从小窗口模式切换回普通模式,会回调Activity/Fragment的onConfigurationChange方法。
  写在前面,有个比较严重的点需要注意,经过国内厂商的魔改,逻辑效果会有点不同:

小窗口模式需要注意:
华为:
activity.isInMultiWindowMode小窗口模式返回true
切换小窗口模式不会调用onConfigurationChanged,会调用onResume
小窗口模式顶部有个状态栏,布局内容在状态栏下
小窗口模式底部没有操作栏

vivo:
activity.isInMultiWindowMode小窗口模式返回true
切换小窗口模式会调用onConfigurationChanged,不会调用onResume
小窗口模式顶部有个状态栏,状态栏覆盖在布局内容上
小窗口模式底部没有操作栏

oppo:
activity.isInMultiWindowMode小窗口模式返回false (问了技术支持,只能通过宽高尺寸来判断)
切换小窗口模式会调用onConfigurationChanged,不会调用onResume
小窗口模式顶部有个状态栏,状态栏覆盖在布局内容上
小窗口模式底部没有操作栏

小米:
activity.isInMultiWindowMode小窗口模式返回true
切换小窗口模式会调用onConfigurationChanged,不会调用onResume
小窗口模式顶部有个状态栏,状态栏覆盖在布局内容上
小窗口模式底部有个操作栏
小窗口模式PopupWindow的showAsDropDown展示的位置异常,只能使用showAtLocation
状态栏高度读取异常:切换小窗口模式切换回来后,状态栏高度读取到的值变小了  105->98
底部导航栏高度读取异常:小窗口模式,一开始读取到130,跳转别的页面后回退读取到142

三星:
直接放弃...和国内的厂商不同,国内的宽高比是固定的,而三星可以随意修改小窗口的宽高,导致适配....无解,这种适配起来,就复杂多了,需要每次切换了大小就重新计算布局。

  由于切换模式会回调其中一个生命周期(onConfigurationChanged/onResume),所以可以在回调的地方进行布局调整,适配界面直到能完整展示全部UI。目前来说,小米的适配是麻烦多了,和其它厂商差别会比较大,所以不能统一适配。

弹窗Dialog/PopupWindow注意

  在实际开发过程中还发现,如果是以上2.2的情况,切换小窗口模式时,Dialog/PopupWindow有可能会被回收为null,但界面上还是展示着,这时候对弹窗的操作都是无效的,并且还可能引发崩溃,所以在Activity/Fragment的onDestroy里面,将界面内的弹窗全部进行dismiss隐藏,避免出现该问题。

完结

  由于我测试使用的只是各个厂商中的一两台手机,所以可能还不是很完全,可能还有别的情况需要适配,这就要等到遇到的时候再来了。
  总的来看,小窗口模式/分屏模式需要进行适配的,并不复杂,监听生命周期调一调界面即可。

微信搜索“A查佣利小助手”,获取支付宝红包、TB/JD/PDD返利最新优惠资讯

wechat(1)(1).png