前言
关于沉浸式,我之前也写过一篇笔记(到处找大佬们总结的资料总结整理出来的),在之前的笔记中也做过实验,但是,最后总结归纳写出的库不尽人意,于是在相应国家政策(在家待着别乱跑)的同时,决定再来捋一捋这个沉浸式,修改一下之前总结时出的差错(估计这次也有问题)。
测试机配置及项目相关配置
- 测试机为谷歌原生机(模拟器):Android 4.4 、Android 5.1 、 Android 9.0 (刘海屏)
- 项目Theme配置
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"/>
- 开发语言为kotlin
- 代码地址:沉浸式测试代码
理论知识
理论知识是实践的基础
关于沉浸式,在安卓这么多版本中,也经历了几次变革,主要分为以下几个阶段:
- 第一阶段:Android 4.4 (API 19) - Android 5.0 (API 21)
- 第二阶段:Android 5.0 (API 21)以上版本
- 第三阶段:Android 6.0 (API 23) 以上版本
所以,安卓4.4以下就别想了
第一阶段
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
在安卓4.4及以上版本,添加了这样的一个FLAG,我们只需要添加这个FLAG即可实现沉浸式,这个阶段实现沉浸式的效果不是很好,主要的实现方式是将状态栏设置为透明并且设置为全屏。让在这个样式下进行沉浸式的适配。
第二阶段
android:statusBarColor(对应的方法为setStatusBarColor)
通过这个方法我们就可以实现我们想要的沉浸式了
第三个阶段
这个阶段主要是为了解决我们给状态栏设置的颜色为亮色时并且状态栏上的文字也为亮色时导致文字看不清楚的问题而出现的。
东西倒是没多少(没往深处看的结论,反正老夫只要实现即可,理论知识的话,下次一定),接下来到了最重要的环节,去验证这些理论知识的正确性。
实践操作
实验是检验真理的唯一标准
这里我只验证以下几种
- 普通Activity的适配
- Activity嵌套多个Fragment(ViewPager)的适配
- Activity带侧边栏的适配
- Activity带侧边栏并嵌套多个Fragment(ViewPager)的适配
其他的情况,下次一定补上。
实验一:普通Activity的适配
普通Activity的适配
未适配时(从左到右依次是4.4、5.1、9.0)
未适配
适配之后(从左到右依次是4.4、5.1、9.0)
已适配
适配代码为
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
activity.window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
//注意要清除 FLAG_TRANSLUCENT_STATUS flag
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
activity.window.statusBarColor = Color.parseColor("#00000000")
//防止底部虚拟导航栏透明化
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
但是,这里我们会看到,我们的内容全部跑到最上面去了,这里我提供两个思路
- 填充一个高度和StatusBar一样的Viwe进去
- 给最上层的View设置PaddingTop,高度和StatusBar一样
我采用的是第二种。核心代码如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
val resourceId = resources.getIdentifier(
"status_bar_height",
"dimen",
"android"
)
val height = resources.getDimensionPixelSize(resourceId)
headerView.setPadding(0, height, 0, 0)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val resourceId = resources.getIdentifier(
"status_bar_height",
"dimen",
"android"
)
val height = resources.getDimensionPixelSize(resourceId)
headerView.setPadding(0, 0 + height, 0, 0)
}
最终实现的效果如下:
最终实现的效果图
是不是很秀?
存在的限制
这里我附加说明几个问题:
- 如果顶部是图片的话,我们就不需要去管顶部的高度了
- 我们设置的headerView的layout_height属性值必须是wrap_content,不然这个View的内容就会被挤出这个View容器(意思就是内容会消失一部分或者全部消失)。
实验二:Activity嵌套多个Fragment(ViewPager)的适配
Activity嵌套多个Fragment(ViewPager)的适配
未适配时(从左到右依次是4.4、5.1、9.0)(从上到下依次是第一个和第二个Fragment)
未适配时的Fragment1
未适配时的Fragment2
适配Activity时
是不是很难看,我们带入上面适配Activity的代码(不管Statusbar高度时),运行看看。
适配Activity之后的Fragment1
适配Activity之后的Fragment2
图片适配的还是挺好看的,但是显示文字的那个还是跑到最上面去了,我们接下去适配StatusBar的高度问题,顶部是图片的Fragment我们不需要去适配高度,所以我们只需要去试Fragment1即可,在Fragment1中写入上面适配高度的代码,运行看看
适配高度之后的Fragment1
可以看到,已经正常显示了。
实验三:Activity带侧边栏的适配
Activity带侧边栏的适配
未适配时(从左到右依次是4.4、5.1、9.0)
打开侧滑菜单时
正常显示时
适配Activity时(从左到右依次是4.4、5.1、9.0)
写入上面的适配Activity的代码,运行看看
打开侧滑菜单时
正常显示时
emmmmm,适配效果很糟糕,那怎么办咧
不要慌,我们首先删除我们布局文件中DrawerLayout的这个属性
android:fitsSystemWindows="true"
然后给NavigationView添加这个属性值
app:insetForeground="@null"
针对4.4到5.0,需要添加如下代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
drawer.fitsSystemWindows = true
drawer.clipToPadding = false
}
那么现在DrawerLayout和NavigationView配置如下
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:openDrawer="start">
....
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:insetForeground="@null"
app:headerLayout="@layout/nav_header_normal_nav"
app:menu="@menu/activity_normal_nav_drawer" />
....
最后,我们分别将侧滑菜单的顶部和主界面的顶部进行高度适配,运行看看。
适配Activity和侧边栏时(从左到右依次是4.4、5.1、9.0)
打开侧滑菜单时
正常显示时
实验四:Activity带侧边栏并嵌套多个Fragment(ViewPager)的适配
Activity带侧边栏并嵌套多个Fragment(ViewPager)的适配
未适配时(从左到右依次是4.4、5.1、9.0)
适配后(从左到右依次是4.4、5.1、9.0)
沉浸式适配出来的效果还是不错的。
总结
那么,经过这次试验,总结如下的配置代码,在适配时挑选使用即可
设置顶部View的Padding的高度为状态栏的高度
fun setTopAdater(resources:Resources,headerView: View) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
val resourceId = resources.getIdentifier(
"status_bar_height",
"dimen",
"android"
)
val statusBarHeight = resources.getDimensionPixelSize(resourceId)
headerView.setPadding(0, statusBarHeight, 0, 0)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val resourceId = resources.getIdentifier(
"status_bar_height",
"dimen",
"android"
)
val statusBarHeight = resources.getDimensionPixelSize(resourceId)
headerView.setPadding(0, 0 + statusBarHeight, 0, 0)
}
}
配置Activity
fun setActivityAdapter(activity: Activity, isSetLightStatusBar: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
activity.window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
activity.window.statusBarColor = Color.parseColor("#00000000")
//防止底部虚拟导航栏透明化
activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
}
配置侧边栏
1、按照上述试验操作设置相关属性值
2、设置代码适配版本
fun setNavigationViewTopAdapter(drawer: DrawerLayout) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
drawer.fitsSystemWindows = true
drawer.clipToPadding = false
}
}
关于第三阶段,大家可自行去搜索(几行代码),最后准备写个库来用的,但是现在太晚了,下次一定。示例代码在笔记顶部有链接,欢迎大佬提出有问题的地方,以便作为菜鸡的我及时改正。
好了,这篇文章先到这里,后期有新的的再补充(客套话)。












网友评论