Android适配刘海屏沉浸式状态栏的一些坑

2023-11-14

在国内做Android开发真的不容易,国内的深度定制“安卓”总能时不时的给你来几个“惊喜”。

起因

18年简直是刘海元年,所有手机都在跟风刘海屏,甚至每个厂商还有自己的一套适配规范。我的初始需求很简单,就是做一个全屏显示的页面,一般情况下只需要开启Android规范的全屏模式就好:

<item name="android:windowFullscreen">true</item>

结果,在真机上测试发现系统为了适配不遮挡内容,默认全屏模式为非刘海屏,就是刘海那栏直接填黑,严重影响观感,这明显不符合我的需求。因此走上了适配刘海的一条不归路。

方案一

经过调试,发现普通模式下(非全屏)是可以将内容正常显示到整个屏幕的,这时候最顶部显示的就是应用默认的 StatusBar,由于状态栏的颜色默认为colorPrimaryDark,也就是说需要手动指定的,而我需要的打倒的效果为沉浸式显示,状态栏颜色需要和内容一致,甚至将内容扩充显示到状态栏上,因此我想到了以下:

<item name="android:windowTranslucentStatus">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>

第一个参数将状态栏透明化,这时候我们的布局内容就会自动扩充到状态栏上,然后再使用第二个参数将状态栏颜色设置成透明,最后在每个布局中动态添加一个高度等于状态栏的自定义view进行占位,搞定。

刘海屏手机上测试,完美,再换回普通手机,GG。发现虽然将状态栏设置成了透明,但是依然存在一个半透明的遮罩,强迫症的我显然不能忍,方案一失败。

方案二

为了解决上述操作下状态栏始终会存在一个半透明的遮罩,进行了一系列调研和尝试,最后发现另外一套方案:

<item name="android:windowTranslucentStatus">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentNavigation">true</item>

和第一种相比,将状态栏透明化关闭,将导航透明化打开。重点是android:windowTranslucentNavigation这个参数,他的作用和android:windowTranslucentStatus类似,可以让内容布局扩充出去,而且影响的不仅仅是StatusBar,还有NavigationBar也就是底部的虚拟按键。

使用这种设置之后,状态栏的半透明遮罩总算是去掉了,但是也带来了一个弊端,那就是内容会填充到NavigationBar上面,也就是说如果用户手机开启了虚拟按键的话,虚拟按键会悬浮在视图之上,这样很容易带来误操作,因此我们需要像之前一样在底部也加入一个高度等于虚拟按键的view进行占位。

这里大概说下统一为布局添加占位view的方法,创建BaseFullScreenActivity重写ActivitysetContentView()方法,在方法中获取到我们设置的布局,将其提取出来,并且重新创建一个LinearLayout,依次装入head、content、foot。核心代码如下:

    override fun setContentView(layoutResID: Int) {
        super.setContentView(layoutResID)
        findViewById<ViewGroup>(android.R.id.content).let {
            val contentGroup = LinearLayout(this).apply {
                layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT)
                orientation = LinearLayout.VERTICAL
            }
            it.setOnApplyWindowInsetsListener { view, windowInsets ->
                view.dispatchApplyWindowInsets(windowInsets)
            }
            //customView
            it.getChildAt(0).apply {
                val lp = LinearLayout.LayoutParams(layoutParams)
                lp.height = 0
                lp.weight = 1f
                layoutParams = lp
                it.removeAllViews()
                contentGroup.addView(this)
            }
            //navigationBar
            contentGroup.addView(View(this).apply {
                layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        getBottomStatusHeight(this@BaseFullScreenActivity))
                setBackgroundColor(Color.BLACK)
            })
            it.addView(contentGroup)
        }
    }

红米6上测试,完美,普通手机上测试,完美。就在我觉得终于搞定了的时候,突然有一天,公司换了一波新测试机。而其中就有刘海屏的小米8。我本着吃饱了没事做的作死精神第一时间对小米8进行了测试。

结果状态栏没问题,可是底部出现了一条黑边,无独有偶,我在小米8上使用GeekBench准备跑分的时候发现同样也出现了黑边。最后测试发现,因为该方案需要手动计算底部虚拟按键高度进行填充,而在小米8上面,无论是否存在虚拟按键,计算结果都是存在虚拟按键高度的!这里真心要吐槽一下MIUI的工程师,什么鬼!

最终方案

最终方案很容易,集以上两种方案的优点,却没有第二种的缺点。设置也一样简单,问我为什么不一开始用这个,因为我不知道啊。直接上配置:

<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>

这里相比方案一多了个设置:android:windowDrawsSystemBarBackgrounds,设置了该方法之后,状态栏上的半透明遮罩直接就消失了。可以说很方便了,可惜不知道,查了很久也没结果。

MIUI10 Bug

通常我们获取当前屏幕高度方法为下:

    val wm = activity.getSystemService(Service.WINDOW_SERVICE) as WindowManager
    val windowSize = Point()
    wm.defaultDisplay.getSize(windowSize)

但是在小米8上,无论是否开启虚拟按键,得到的屏幕高度都是存在虚拟按键的高度。不知道是否为故意设置的安全区域,总之在使用过程中已经发现了好几款市面上的三方App受到该bug影响导致显示异常

写在最后

这里的三个方案可以对应不同的使用场景,通过这些坑也让我对StatusBarNavigationBar有了深入的了解。还有就是小米的那个bug,真的无解,而且会影响到一些会用到屏幕尺寸的计算,只能后续再看看了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android适配刘海屏沉浸式状态栏的一些坑 的相关文章

  • Golang 数据结构 —— 字典

    Golang 数据结构 字典 字典存储 key value 对 Go提供了非常方便的实现 内置的map类型 本文增强内置的map类型 添加便捷的操作用于获取或改变其内容 创建ItemDictionary泛型 并发安全的 能够生成任何具体类型

随机推荐

  • linux配置svn 版本管理之创建仓储和权限管理

    1 安装 yum install subversion 2 配置 2 1 创建仓库 我们这里在 home下建立一个名为svn的仓库 repository 以后所有代码都放在这个下面 创建成功后在svn下面多了几个文件夹 root local
  • 拉链表的设计与实现

    一 什么是拉链表 针对订单表 订单商品表 流水表 这些表中的数据是比较多的 如果使用全量的方式 会造成大量的数据冗余 浪费磁盘空间 所以这种表 一般使用增量的方式 每日采集新增的数据 在这注意一点 针对订单表 如果单纯的按照订单产生时间增量
  • 前台想后台传数组与解析

    var info JSON stringify ids ajax type POST url url data ids info flowId flowId flowName flowName name name html html dat
  • 多数据源的配置

    一 yml的数据源配置 配置两个数据源一个叫master主数据源 一个是slave从数据源 默认是主数据源 从数据源需要做切换 datasource master driver class name com microsoft sqlser
  • 2023年苹果IOS开发者证书申请(已实测准确)

    一 创建苹果开发者账号 苹果开发者官网 https developer apple com 注册苹果账号apple id 开启双重认证 需在一台IOS手机 iPad操作 在App Store下载Apple Developer APP 进行注
  • 怎么关闭csv的科学计数法

    一 问题背景 身份证号码 订单号这些都是很长的字符串 在csv文件中经常以科学计数法出现 要取消科学计数法 二 解决方案 笔者的方案最终是以xls格式保存下来 如果大家需要以csv文件格式保存 那么笔者的解决方案是无效的 而且有必要了解一点
  • 外网SSH远程连接linux服务器,看这一篇就够了

    文章目录 视频教程 1 Linux CentOS安装cpolar 2 创建TCP隧道 3 随机地址公网远程连接 4 固定TCP地址 5 使用固定公网TCP地址SSH远程 转载自内网穿透工具的文章 无公网IP SSH远程连接Linux Cen
  • Django:四、Djiango如何连接使用MySQL数据库

    一 安装数据库第三方插件 安装下载mysql第三方插件 pip install mysqlclient 二 创建MySQL数据库 ORM可以帮助我们做两件事 创建 修改 删除数据库中的表 不用写SQL语句 但无法创建数据库 操作表中的数据
  • 踩坑解决:web Server Traceback(most recent call last)builtins. Attributeerror: int object has no attribut

    解决方法 尝试将Twisted 版本重新安装成 18 9 0 卸载Twisted命令 pip uninstall Twisted 安装指定版本Twisted pip install Twisted 18 9
  • centos7 合并pdf命令

    格式 命令行 要合并文件 合并后的文件名 pdfunite pdf all pdf pdfunite 1 pdf 2 pdf all pdf
  • 已解决ERROR: No matching distribution found for gradio==3.23

    已解决stderr ERROR Could not find a version that satisfies the requirement gradio 3 23 ERROR No matching distribution found
  • C/C++就业方向与技能需求整理-实习篇

    前言 本文主要面向计算机类本科生同时想要寻求偏向C 相关的职业 提供就业方向参考以及需要学习的技能 以下资料来自牛客网 更于 2022 4 1 网络研发实习生 岗位职责 1 通过软件开发实现数据中心网络和骨干网络的管理和运维自动化 确保网络
  • 安装centos7报错:/dev/root does not exist 问题处理过程

    最近自己做练习的一台实体机服务器硬盘坏了 想着换了重新装一下 结果就是碰壁 折腾了好几天 一直以为是写U盘的工具有问题 报的错也是奇怪 提示 dev root does not exist 并且前面出现n排同样的警告 Warning dra
  • 用Java写一个公司员工管理系统!

    用Java写一个公司员工管理系统 今天看CSDN发现写管理系统的文章不少 我在这里也给大家用java写一篇 当然这里只是最简单的那种qwq 核心功能 对员工各项信息的管理 采用属性文件 资源文件 支持中文简体和英文 目录 第一步 创建一个记
  • 李宏毅 深度学习作业3 CNN

    通过CNN卷积神经网络对食物图片进行分类 训练集与验证集中图片格式为 类别 编号 jpg Import 需要的套件 import os import numpy as np import cv2 import torch import to
  • mysql aio与并发执行线程_mysql 原理 ~ 线程与IO

    一 简介 今天来聊聊具体的线程和IO 二 具体线程与作用 1 master thread mysql的主要工作触发线程 1 redo and binlog日志 2 合并插入缓冲 3 脏页的刷新 4 undo页回收 5 产生一个ckp点 2
  • 从Python到计算机视觉:入门指南

    Python一直是计算机科学领域中最受欢迎的语言之一 它不仅易于学习和使用 而且具有广泛的应用领域 尤其是计算机视觉方面 本文将为读者提供一份详细的入门指南 帮助初学者了解Python和计算机视觉的基础知识和应用 安装Python 要开始使
  • 数据结构进阶

    并查集 朴素版 const int N 1e5 10 int p N 返回x的祖宗节点 int find int x 只有根节点才会有p x x if p x x p x find p x return p x 初始化 void init
  • 咋搭建域控服务器,Active Directory虚拟机搭建域控服务器环境

    前言 还是和上一章一样 痛苦过后还是记录下给后来人提供便利为妙 虚拟机选择 建议Hyper V或者VMware 系统选择 建议WIindows Server 2003及以上 我这里是使用VMware Workstation Pro Wind
  • Android适配刘海屏沉浸式状态栏的一些坑

    在国内做Android开发真的不容易 国内的深度定制 安卓 总能时不时的给你来几个 惊喜 起因 18年简直是刘海元年 所有手机都在跟风刘海屏 甚至每个厂商还有自己的一套适配规范 我的初始需求很简单 就是做一个全屏显示的页面 一般情况下只需要