Android 15 应用适配默认全屏的行为变更(Android V的新特性)

简介

Android V 上默认会使用全面屏兼容方式,影响应用显示,导致应用内跟导航标题重合,无法点击上移的内容。

默认情况下,如果应用以 Android 15(API 级别 35)为目标平台,在搭载 Android 15 的设备上,应用默认采用全屏。

解决方案

先说适配方案,后面有官方文档的介绍说明变更内容、应用自查方法和配置建议。

方法:实现无边框应用。

如何检查应用尚未实现无边框

如果您的应用还没有全面屏,那么您很可能会受到影响。除了针对已经采用无边框的应用的情况之外,您还应考虑以下事项:

  • 如果您的应用在 Compose 中使用 Material 3 组件 (androidx.compose.material3)(例如 TopAppBarBottomAppBarNavigationBar),这些组件可能不会受到影响,因为它们会自动处理边衬区。
  • 如果您的应用在 Compose 中使用 Material 2 组件 (androidx.compose.material),这些组件不会自动处理边衬区。不过,您可以访问边衬区,并手动应用边衬区。在 androidx.compose.material 1.6.0 及更高版本中,使用 windowInsets 参数为 BottomAppBarTopAppBarBottomNavigationNavigationRail 手动应用边衬区。同样,对 Scaffold 使用 contentWindowInsets 参数。
  • 如果您的应用使用视图和 Material 组件 (com.google.android.material),则大多数基于视图的 Material 组件(例如 BottomNavigationViewBottomAppBarNavigationRailViewNavigationView)均可处理边衬区,无需执行额外的操作。不过,++如果使用 AppBarLayout,则需要添加 android:fitsSystemWindows="true"。++
  • 对于自定义可组合项,请手动将边衬区作为内边距应用。如果您的内容在 Scaffold 内,您可以使用 Scaffold 内边距值使用边衬区。否则,请使用某个 WindowInsets 应用内边距。
  • 如果您的应用使用视图和 BottomSheetSideSheet 或自定义容器,请使用 ViewCompat.setOnApplyWindowInsetsListener 应用内边距。对于 RecyclerView,请使用此监听器应用内边距,并添加 clipToPadding="false"

(一)针对传统的Java传统视图参考方案(无Compose使用)

【Java】创建界面时,设置属性 fitsSystemWindows属性为 true

如果做成插件化,没有使用Activity布局可配置,如PreferenceScreen中没有android:fitsSystemWindows="true"配置,且设置activitybase.xml线性布局此属性也无法解决,可选择在onCreateView生命周期中渲染界面。

java 复制代码
public class MainPref extends PreferenceFragmentBase
        implements Preference.OnPreferenceChangeListener {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = super.onCreateView(inflater, container, savedInstanceState);
        Log.d(TAG, "onCreateView: rootView = "+ rootView + ", setFitsSystemWindows=true.");
        if (rootView != null) {
            rootView.setFitsSystemWindows(true);
        }
        return rootView;
    }

Note:在一个包含 Fragment 的 Activity 中,onCreate()方法会先被调用,然后再调用 Fragment 的onCreateView()方法。

(二)针对Compose的方案:

1、在build.gradle 添加编译依赖

dependencies {
    implementation "androidx.core:core-ktx:1.6.0" // 当前释放最新应该是1.6.0,可以需修改成以后更新版本
    implementation "androidx.appcompat:appcompat:1.3.1"
    implementation "androidx.constraintlayout:constraintlayout:2.0.4"
}

2、【XML】修改manifest配置布局 fitsSystemWindows属性为 true

XML 复制代码
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:id="@+id/main_layout"
    tools:context=".MainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>

3、【Java】修改Activity创建逻辑

默认情况下,每个 ComposeView 都会使用 WindowInsetsCompat 级别使用的所有边衬区。如需更改此默认行为,请将 ComposeView.consumeWindowInsets 设置为 false

Kotlin 复制代码
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //拿到自定义id的布局进行操作
    ConstraintLayout mainLayout = findViewById(R.id.main_layout);

    ViewCompat.setOnApplyWindowInsetsListener(mainLayout, (v, windowInsets) -> {
        WindowInsetsCompat insetsCompat = ViewCompat.getRootWindowInsets(v);
        if (insetsCompat != null) {
            Insets insets = insetsCompat.getInsets(WindowInsetsCompat.Type.systemBars());
            Log.d(TAG, "left = " + insets.left + ", top = " + insets.top + 
                ", right = " + insets.right + ", bottom = " + insets.bottom);

            v.setPadding(insets.left, insets.top, insets.right, insets.bottom);
        } else {
            Log.d(TAG, "insetsCompat is null");
        }

        // 获取 WindowInsetsControllerCompat 实例
        WindowInsetsControllerCompat windowInsetsController = ViewCompat.getWindowInsetsController(v);

        if (windowInsetsController != null) {
            // 设置状态栏图标和文字为深色
            windowInsetsController.setAppearanceLightStatusBars(true);
        }

        // Return CONSUMED if you don't want want the window insets to keep passing
        // down to descendant views.
        return WindowInsetsCompat.CONSUMED;
    });
}

官方文档

1、变更说明:行为变更:以 Android 15 或更高版本为目标平台的应用 | Android Developers

2、全面屏&无边框应用自检步骤:检查应用是否已采用全屏的检查步骤 | Android Developers

3、配置建议:稳定配置 | Android Developers (google.cn)

UI案例

1、在Android 14的设备上,如果应用没有升级API版本则不会出现Android 15 SDK全面屏导致的负面影响:
以 Android 14 为目标平台且在 Android 15 设备上非全屏的应用

全屏强制应用

2、当API和系统都是Android 15时,会受到全面屏负面影响,导致top Bar和导航栏异常重合问题。

由于 Android 15 全屏强制措施,现在许多元素被状态栏、"三按钮"导航栏或刘海屏隐藏。隐藏界面包括 Material 2 顶部应用栏、悬浮操作按钮和列表项。
以 Android 15(API 级别 35)为目标平台且在 Android 15 设备上为全屏的应用

无边框应用

3、在 Android 15 设备上采用无边框应用,并应用边衬区以便不隐藏界面。
以 Android 15(API 级别 35)为目标平台的应用,在 Android 15 设备上采用无边框应用

如需了解应用边衬区的其他注意事项,请参阅无边框视图无边框 Compose 指南。

配置说明

如果您的应用以 Android 15 或更高版本为目标平台,Configuration 将不再排除系统栏。如果您在 Configuration 类中使用屏幕尺寸计算布局,则应根据需要将其替换为合适的 ViewGroupWindowInsetsWindowMetricsCalculator 等更好的替代方案。

从 API 1 开始,Configuration 一直可用。它通常从 Activity.onConfigurationChanged 获取。它可提供窗口密度、方向和大小等信息。从 Configuration 返回的窗口大小的一个重要特征是它之前排除了系统栏。

配置大小通常用于资源选择(如 /res/layout-h500dp),这仍然是一个有效的用例。不过,我们一直不建议将其用于布局计算。如果这样做,您应该立即离开。您应该根据自己的使用场景,将 Configuration 替换为更合适的代码。

如果您使用其计算布局,请使用适当的 ViewGroup,例如 CoordinatorLayoutConstraintLayout。如果您使用它来确定系统导航栏的高度,请使用 WindowInsets。如果您想知道应用窗口的当前大小,请使用 computeCurrentWindowMetrics

以下列表介绍了受此更改影响的字段:

相关推荐
拭心1 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
带电的小王3 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡3 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道4 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库5 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道5 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe5 小时前
Android Hook - 动态加载so库
android
居居飒6 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
晓纪同学9 小时前
QT创建一个模板槽和信号刷新UI
开发语言·qt·ui
Henry_He9 小时前
桌面列表小部件不能点击的问题分析
android