这里简单分享下我在适配 Android 15 的一些心得。
本篇文章不会介绍 Android 15 所有的更新。
更新应用的 build 配置
// AGP >= 7.0.0android { compileSdk 35 ... defaultConfig { targetSdk 35 }}
对于较老的项目,这里建议将AGP升级到8.0.0以上,并且更新Java的版本到17以上。
由于一些老的项目还使用的是ButterKnife
,这里建议用 ViewBinding 进行替换。
在更新完build配置后,程序大概率会报错,根据报错信息一一修改就好。
Edge to Edge 适配
在 Android 15或更高版本的设备上,以 SDK 35 或更高版本为目标平台,系统会自动为该应用启用无边框模式。
该模式下,窗口的顶部以及底部都会以全屏的形式默认展开。
如何检查应用尚未实现无边框
如果您的应用还没有全面屏,那么您很可能会受到影响。在 除了针对已经采用无边框的应用的情况之外, 请考虑以下事项:
-
如果您的应用使用 Material 3 组件 ( androidx.compose.material3),例如 TopAppBar, BottomAppBar 和 NavigationBar,那么这些组件可能不 会受到影响,因为它们会自动处理边衬区。
-
如果您的应用使用 Material 2 组件 ( androidx.compose.material),那么这些组件 不会自动处理边衬区。不过,您可以使用边衬区 并手动应用这些设置在 androidx.compose.material 1.6.0 中 然后使用 windowInsets 参数手动应用边衬区 BottomAppBar、TopAppBar、 BottomNavigation 和 NavigationRail。 同样,对以下内容使用 contentWindowInsets 形参: Scaffold。
-
如果您的应用使用视图和 Material 组件 (com.google.android.material),大多数基于 View 的 Material 如 BottomNavigationView、BottomAppBar、 NavigationRailView 或 NavigationView,处理边衬区,不需要 额外工作。但是,您需要将 android:fitsSystemWindows=“true” 如果使用 AppBarLayout,则会发生此错误。
-
对于自定义可组合项,请手动将边衬区作为内边距应用。如果您的 内容位于 Scaffold 内,因此您可以使用 Scaffold 来使用边衬区 内边距值。否则,使用 WindowInsets。
-
如果您的应用使用的是视图和 BottomSheet、SideSheet 或自定义 使用 ViewCompat.setOnApplyWindowInsetsListener。对于 RecyclerView,使用此监听器应用内边距,同时添加 clipToPadding=“false”。
使用 Padding 适配
对每个界面顶部以及底部增加padding,使其不会被遮挡。
以下是我在项目中使用的代码(仅供参考):
-
新增
ViewUtil
在其中新增applyWindowInsets
的方法。class ViewUtil {/*** Set padding to this view.** @param view The View against which to invoke the method.* @param insetsType Bit mask of WindowInsetsCompat.Types to query the insets for.*/public static void applyWindowInsets(View view, int insetsType) {ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {Insets insets = windowInsets.getInsets(insetsType);v.setPadding(insets.left, insets.top, insets.right, insets.bottom);// remove insets listenerViewCompat.setOnApplyWindowInsetsListener(view, null);return WindowInsetsCompat.CONSUMED;});}} -
创建
IEdgeToEdge
的 Interface,以供 Activity 和 Fragment 实现其中的方法。public interface IEdgeToEdge {@Nullable@IdResdefault Integer topLayoutResId() {return null;}@Nullable@IdResdefault Integer bottomLayoutResId() {return null;}void adapterEdgeToEdge();} -
在
BaseActivity
或者BaseFragment
中实现IEdgeToEdge
的接口public BaseActivity extends AppCompatActivity implements IEdgeToEdge {@Nullable@Overridepublic Integer topLayoutResId() {return R.id.app_bar; // top layout default resId}@Nullable@Overridepublic Integer bottomLayoutResId() {return R.id.bottom_layout; // bottom layout default resId}@Overridepublic void adapterEdgeToEdge() {val topLayoutResId = topLayoutResId();if (topLayoutResId != null) {val topLayout = findViewById(topLayoutResId);if (topLayout != null) {// Top layout insetsType is WindowInsetsCompat.Type.statusBarsViewUtil.applyWindowInsets(topLayout, WindowInsetsCompat.Type.statusBars());}}val bottomLayoutResId = bottomLayoutResId();if (bottomLayoutResId != null) {val bottomLayout = findViewById(bottomLayoutResId);if (bottomLayout != null) {// Top layout insetsType is WindowInsetsCompat.Type.navigationBars()ViewUtil.applyWindowInsets(bottomLayout, WindowInsetsCompat.Type.navigationBars());}}}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {// Here is your init view codes...// 如果是Fragment,请在 `onViewCreated` 中调用,确保 `findViewById` 可以找到对应的IdadapterEdgeToEdge();}}处理到这里,如果你的代码写的足够统一与规范,那么已经基本完成了适配。不过上述的代码并不适用于所有画面
-
对特有的画面适配
你需要在该画面中重写
topLayoutResId()
以及bottomLayoutResId()
,将你想调整的控件id填入其中即可。需要注意的是对于可滚动的控件,例如 RecycleView,建议是将 padding 设置为 RecycleView 本身,而不是他所在的 Layout,这样可以使 RecycleView 的可视化区域最大,
其他
-
在 Android 15 中 DialogAlert 弹出后,Alert 会发生上下抖动
原因:在
dialog.setOnShowListener
中做了某些操作,导致 Alert 的高度发生变化。解决方案:将
dialog.setOnShowListener
中的代码直接放在dialog.show()
之后即可。
以上就是我在对应某项目的 Android 15 时遇到的全部问题。欢迎补充。