准备升级到Android16,自适应布局应该如何适配

背景

对于面向谷歌开发的牛马来讲,必须时刻关注谷歌的新特性以及新政策,因为如果不这么做的话,你的应用迟早会在play商店里面遭到下架的警告,这不现在已经6月了,还有两个半月就要到八月31号了,虽然官方目前还没有明确说明,但是按照过去两年的时间线,有一件事情不得不马上要提到todo List里面去了,那就是targetSdkVersion需要升级到36

而今天这篇文章要讨论的是如何去适配Android16里面的其中一个特性--自适应布局,官方文档上有一段说明,大概的意思是Android 平台正朝着应用需要适应各种屏幕方向、显示屏尺寸和宽高比的模式发展,固定屏幕方向或限制尺寸调整会阻碍应用在大屏设备上的适应性,对于以 Android 16(API 级别 36)为目标平台的应用,屏幕方向、尺寸可调整性和宽高比限制不再适用于最小宽度 >= 600dp 的显示屏,无论宽高比或用户偏好的屏幕方向如何,应用都会填满整个显示窗口,且不会采用竖条模式。

值得注意的是,Android16提供了一个开关,关闭后你的应用将不会受到这个特性的影响,以前怎么样现在还是怎么样,但是到了Android17,这个开关也将被废弃,也就是Android17就要强制打开这个特性了,根据以往的经验就能知道,凡事带开关的特性,适配起来的工作量都不会小,比如edge-to-edge,16kb或者预测性返回,所以我们也应当好好规划下这个自适应布局应该如何去适配

即将被忽略的属性与API

其实如何你的应用有发布至谷歌市场,一定会在后台看见过谷歌早在几个月前就有给你的app发过一个用户体验类型的整改建议,内容就是将项目中的尺寸调整以及屏幕方向的限制去除掉

那么具体是哪些限制呢,官方也列出来了

AndroidManifest 属性

属性 说明
android:screenOrientation 所有锁定值均被忽略(portrait、landscape、sensorPortrait 等)
android:resizableActivity false 设置不再生效
android:minAspectRatio 无效果
android:maxAspectRatio 无效果

运行时 API

API 说明
setRequestedOrientation() 被忽略
getRequestedOrientation() 返回值不再代表实际行为

被忽略的 screenOrientation 取值

复制代码
portrait, reversePortrait, sensorPortrait, userPortrait,
landscape, reverseLandscape, sensorLandscape, userLandscape

例外情况

以下三种情况下,方向/尺寸限制不会被忽略

例外 条件 说明
游戏 android:appCategory 标记为 game 游戏类应用豁免
用户明确选择 用户在设备宽高比设置中主动启用 用户自主决定
小屏设备 屏幕最小宽度 < 600dp(sw600dp) 手机等小屏设备不受影响

适配方案

方案一:临时豁免,仅适用于Android16

这个就是上面提到过的开关,到了Android17后,这个开关将会无效,具体怎么设置呢?看代码 在 <activity><application> 级别添加属性,暂时恢复旧行为:

这种方式只能作为过渡方案,并不能作为最终方案,只有当你的项目适配工作量太大,或者存在部分三方sdk无法短期适配的时候,才可以使用,给自己留出一些适配时间

方案二:自适应布局改造(Compose)

引入 WindowSizeClass

Compose Material 3 自适应布局组件

组件 用途 行为
NavigationSuiteScaffold 自适应导航 紧凑→底部导航栏,展开→侧边导航栏
ListDetailPaneScaffold 列表-详情 紧凑→单窗格,展开→双窗格并排
SupportingPaneScaffold 辅助窗格 主窗格+辅助窗格自适应

方案三:自适应布局改造(View)

Compose的方案是挺方便,但是绝大多数项目应该还停留在传统View的层面上,对于这类项目,应该如何适配?

使用 SlidingPaneLayout

利用 ConstraintLayout 百分比布局

动态判断布局

Configuration 自适应 + 备用布局资源

使用 Android 资源限定符提供多套布局:

方案四:相机预览专项适配

1.使用 CameraX 的 PreviewView

2.使用 Camera2 时手动处理方向

参考文档: 管理相机预览

方案五: Activity 重建与状态保存

现在既然不固定方向了,那么设备自然会经常会旋转,旋转后的Activity会重建,里面的状态必须好好保存一下

ViewModel + SavedStateHandle

onSaveInstanceState

验证方案

启用兼容性标志快速测试

在开发阶段,通过adb强制启用行为,可以提前发现问题:

使用 DeviceConfigurationOverride 测试

Compose 1.7+ 支持在单台设备本地模拟不同配置:

可调整大小模拟器

Android Studio提供可调整大小模拟器,可以切换不同分辨率大小的屏幕,模拟不同的设备

方式就是在模拟器的设备里面,选择Displays,添加不同的display配置就好了

最后来点吐槽

文章写到这,整个适配过程差不多也结束了,谷歌真是一天天不给人活路,这种适配对于老项目,尤其是内部穿插着各种二方库,三方库的app来讲,简直是个灾难。。。可以说比16kb还恶心,16kb不管咋样,不会让你去改业务代码,顶多哪个库升级了改些废弃的api就好了,但是这个适配,没那么简单,业务代码多多少少需要动到一些,对于维护过老项目,那种屎山项目的人都清楚,业务代码随便改一行动一行,带来的后果可能都是很可怕的,坑估计是少不了的了。。。

相关推荐
神仙别闹1 小时前
基于 PHP + MySQL 图书库存管理系统
android·mysql·php
zhangphil1 小时前
Android内存回收:GC、kswapd 和 mm_vmscan_direct_reclaim概述
android
plainGeekDev1 小时前
ContentProvider → Room + Repository
android·java·kotlin
plainGeekDev2 小时前
SQLite 手动升级 → Room Migration
android·java·kotlin
MemoriKu2 小时前
Flutter 相册 APP 视频模态稳定化实战:从视频抽帧、Embedding 元数据到 Android 真机启动修复
android·开发语言·前端·flutter·架构·音视频·embedding
Che2n3JigW2 小时前
Now in Android:它不是最佳实践,而是大型 Android 工程实践的展示
android·architecture·now in android
故渊at2 小时前
第三板块:Android 图形渲染与窗口体系 | 第十三篇:SurfaceFlinger 与 VSYNC 信号机制
android·图形渲染·surfaceflinger·帧率·窗口体系
Che2n3JigW2 小时前
Now in Android Feature 模块分析:一个功能是如何被组织起来的?
android·udf·architecture·now in android·modularization·feature module
Che2n3JigW2 小时前
Now in Android 项目结构分析:这个 App 是如何搭建起来的?
android·architecture·now in android·modularization·structure