Android折叠屏适配

1,299 阅读4分钟

1. 折叠屏为什么需要适配

折叠屏在视觉效果来说就是,屏幕变大了,手机变平板了。这样就要求我们的APP在可折叠设备展开时,当前应用页面必须无缝延续到另一个屏幕,并可自动调整大小匹配新的布局,也就是说,应用程序需要准备好在多个屏幕(不同分辨率、密度等)之间切换。

折叠屏之所以需要适配,是因为我们的应用有可能在运行的过程中,所在的屏幕尺寸发生了变化,这种情况对现有项目多少都会产生一些问题。

其实这种情况并不是折叠屏出现之后才有的,应用的纵向横向切换也会发生同样的情况,只不过很多应用都强制纵向,不需要处理这种适配了。

2. 折叠屏适配的本质

折叠屏适配的本质是:当应用运行时,屏幕的尺寸、密度或比例发生了变化,应用能够继续在变化后的屏幕上正常显示和正常运行。

产品和设计

  • 如何更好的利用屏幕空间?
  • 如何展示才不会使页面显得空洞?
  • 展开和折叠时分别怎么展示?
  • 展开后如何过度?

开发同学

  • 页面是否显示正常?
  • 是否按产品和设计的预期显示?

因此对于我们开发同学来说,对折叠屏的适配首先要确定一个预期,即要先确定好交互和设计,才能评估工作。因此"折叠屏的适配先是一个设计问题,然后才是一个适配问题"。

3. 适配指导

  • 相对单位:为了适应不同屏幕尺寸和不同使用场景,使用绝对单位容易出现问题。
  • 断点:断点可以看做是临界点,比如屏幕宽度小于这个宽度时显示一个样式,大于这个宽度时显示一个样式。
  • 应用支持自适应能力 建议应用支持可变比例显示(resizeable),在可预见的屏幕比例范围内,都可以做到良好适配。
// 在manifest文件的或节点中设置android:resizeableActivity的值为true,可声明应用支持自适应能力
<application
    android:resizeableActivity="true"
    >
  • 设置应用支持的最大比例和最小比例适配 当 resizeableActivity 取 false 时,展开折叠屏可能变成这样的效果,这个效果类似于在 ipad 上使用不兼容的 iPhone 应用,这个四周用黑色填充的模式,叫兼容模式。

兼容模式的显示和最大支持比例 maxAspectRatio 有关,当屏幕比例超过 maxAspectRatio 时才会用黑边填充,官方建议把 maxAspectRatio 设为 2.4(12:5)。

Android 8.0 以下版本,在 manifest 文件的 application 节点中增加 meta-data 数据,设置最大支持比例:

// maxaspecratio:2.4(2.4表明在主副屏下满屏显示)
<meta-data android:name="android.max_aspect" android:value="2.4" />

// 声明为1.0即表示在展开态大屏下满屏显示
<meta-data android:name="android.min_aspect" android:value="1.0" />

Android 8.0 及以上版本,在manifest文件的activity节点中增加android:MaxAspectRatio属性,声明最大支持比例:

<activity android:maxAspectRatio="2.4"
          android:minAspectRatio="1.0">
          ...
</activity>
  • 切换显示比例应用不重启适配 折叠/展开的操作过程将触发系统向应用发送新布局的配置更改,包括smallestScreenSize,screenSize 和 screenLayout的配置 折叠屏展开--折叠之后Activity的生命周期,可以发现Activity会销毁后重建
onPause()->onStop()->onDestory()->onCreate()->onStart()->onResume()

如果想禁止Activity销毁重建,则需要在AndroidManifest中对Activity的configChanges进行如下的配置:

android:configChanges="screenSize|smallestScreenSize|screenLayout"

这个时候折叠展开--折叠会走Activity#onConfigurationChanged,更新视图布局、重新加载资源。通过此方法即能实现在系统不重启Activity的情况下重置UI。总的来说,折叠屏的适配有点类似平板+旋转屏的综合体,也需要配置文件+多布局。

public void onConfigurationChanged(Configuration newConfig) {
    if(FoldableDeviceUtil.isFold()) {
        //列表
    } else {
        //瀑布流
    }
}

可折叠设备没有android api或回调可以让我们知道当前处于折叠模式还是展开模式的。详细的判断方法可以参考下面的方法:

object FoldableDeviceUtil {
    //1. 官方没有给我们提供api的
    // 2.只能去检测 针对的机型
    val application = AppGlobals.get()!!

    fun isFold(): Boolean {
        return if (TextUtils.equals(Build.BRAND, "samsung") && TextUtils.equals(
                Build.DEVICE,
                "Galaxy Z Fold2"
            )
        ) {
            return HiDisplayUtil.getDisplayWidthInPx(application) != 1768
        } else if (TextUtils.equals(Build.BRAND, "huawei") && TextUtils.equals(
                Build.DEVICE,
                "MateX"
            )
        ) {
            return HiDisplayUtil.getDisplayWidthInPx(application) != 2200
        } else if (TextUtils.equals(Build.BRAND, "google") && TextUtils.equals(
                Build.DEVICE,
                "generic_x86"
            )
        ) {
            return HiDisplayUtil.getDisplayWidthInPx(application) != 2200
        } else {
            true
        }

    }
}

对不同尺寸屏幕适配过程中,为了确保在折叠屏各个屏幕形态下获取最佳的布局显示效果,应用界面正确、美观的布局和显示,包含如下:

  1. 布局能够根据屏幕适当地调整大小;
  2. 根据屏幕配置提供合适的UI布局;
  3. 提供可正常缩放的位图;
  4. 基于自适应尺寸的wrap_content、match_parent、weight避免固定的尺寸单位;
  5. 使用基于控件相对位置的布局,现在更加推荐使用ConstraintLayout,对于布局性能以及扁平化更具有优势;
  6. 考虑使用自动拉伸的.9图或者使用矢量图,矢量图可以保证图片不受拉伸影响而导致失真。