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
}
}
}
对不同尺寸屏幕适配过程中,为了确保在折叠屏各个屏幕形态下获取最佳的布局显示效果,应用界面正确、美观的布局和显示,包含如下:
- 布局能够根据屏幕适当地调整大小;
- 根据屏幕配置提供合适的UI布局;
- 提供可正常缩放的位图;
- 基于自适应尺寸的wrap_content、match_parent、weight避免固定的尺寸单位;
- 使用基于控件相对位置的布局,现在更加推荐使用ConstraintLayout,对于布局性能以及扁平化更具有优势;
- 考虑使用自动拉伸的.9图或者使用矢量图,矢量图可以保证图片不受拉伸影响而导致失真。