Android 全面屏处理(适配挖孔屏刘海屏) kotlin

Posted 时寒很苦恼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 全面屏处理(适配挖孔屏刘海屏) kotlin相关的知识,希望对你有一定的参考价值。

测试机:

android 11 的 Xiaomi MI MAX 3
Android 12 的 Xiaomi K40 Pro

测试方法:

1. 该方法在api30后提示已经过时 在onCreat()方法中,setContentView()前使用。

window.setFlags(
    WindowManager.LayoutParams.FLAG_FULLSCREEN,
    WindowManager.LayoutParams.FLAG_FULLSCREEN
)

测试结果:Android11和Android12均有效,但Android12的挖孔屏区域无效

2. 沉浸模式,查询到:Android系统到了4.4以后才提供沉浸式体验的支持。当设置透明效果后,4.4以下无效果,4.4~5.0全透明,5.0以上半透明;Android沉浸式模式的本质就是全屏化。

	//该方法是从官网复制过来的,效果不如意
    private fun hideSystemBars() 
        val windowInsetsController =
            ViewCompat.getWindowInsetsController(window.decorView) ?: return
        // Configure the behavior of the hidden system bars
        windowInsetsController.systemBarsBehavior =
            WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        // Hide both the status bar and the navigation bar
        windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
    

测试结果:Android11无效,Android12有效,Android12的挖孔屏区域无效。Android11获取windowInsetsController为null

	//这是从别人那里拷过来的(csdn):https://blog.csdn.net/qq_32664007/article/details/126279919
    private fun hideSystemBars(window: Window) 
        //隐藏状态栏和导航栏 以及交互
        WindowInsetsControllerCompat(window, window.decorView).let 
            //隐藏状态栏和导航栏
            it.hide(WindowInsetsCompat.Type.systemBars())
            //交互效果
            it.systemBarsBehavior =
                WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        
    

测试结果:Android11无效,Android12有效,Android12的挖孔屏区域无效。

3.该方法在ide里提示已过时,在官网上未提示

val decorView = window.decorView
decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
        or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
        or View.SYSTEM_UI_FLAG_FULLSCREEN
        or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)

测试结果:Android11和Android12均有效,但Android12的挖孔屏区域无效

4.该方法对测试机均有部分效过

WindowCompat.setDecorFitsSystemWindows(window, false)

测试结果:Android11和Android12的activity绘制区域均将状态栏的区域绘制成功,但状态栏依然透明显示,Android12的挖孔屏区域无效,效果如图(按钮绘制在状态栏的位置上):

5.使用主题

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

测试结果:Android11有效,Android12有效,Android12的挖孔屏区域无效。

6.挖孔屏处理方式

//允许window 的内容可以上移到刘海屏状态栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) 
    val lp = window.attributes
    lp.layoutInDisplayCutoutMode =
        WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
    window.attributes = lp

测试结果:Android12 挖孔屏有效

封装成工具类:

/**
 * 沉浸模式(全屏模式)
 * 设置全屏的方法
 * 参数window在activity或AppCompatActivity都带有
 */
fun immersionFull(window: Window) 
    hideSystemBars(window)
    useSpecialScreen(window)

/**
 * 隐藏状态栏,显示内容上移到状态栏
 */
private fun hideSystemBars(window: Window) 
    //占满全屏,activity绘制将状态栏也加入绘制范围。
    //如此即使使用BEHAVIOR_SHOW_BARS_BY_SWIPE或BEHAVIOR_SHOW_BARS_BY_TOUCH
    //也不会因为状态栏的显示而导致activity的绘制区域出现变形
    //使用刘海屏也需要这一句进行全屏处理
    WindowCompat.setDecorFitsSystemWindows(window, false)
    //隐藏状态栏和导航栏 以及交互
    WindowInsetsControllerCompat(window, window.decorView).let 
        //隐藏状态栏和导航栏
        //用于WindowInsetsCompat.Type.systemBars()隐藏两个系统栏
        //用于WindowInsetsCompat.Type.statusBars()仅隐藏状态栏
        //用于WindowInsetsCompat.Type.navigationBars()仅隐藏导航栏
        it.hide(WindowInsetsCompat.Type.systemBars())
        //交互效果
        //BEHAVIOR_SHOW_BARS_BY_SWIPE 下拉状态栏操作可能会导致activity画面变形
        //BEHAVIOR_SHOW_BARS_BY_TOUCH 未测试到与BEHAVIOR_SHOW_BARS_BY_SWIPE的明显差异
        //BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE 下拉或上拉的屏幕交互操作会显示状态栏和导航栏
        it.systemBarsBehavior =
            WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    

/**
 * 扩展使用刘海屏
 */
private fun useSpecialScreen(window: Window) 
    //允许window 的内容可以上移到刘海屏状态栏
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) 
        val lp = window.attributes
        lp.layoutInDisplayCutoutMode =
            WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
        window.attributes = lp
    

然后资源目录的主题文件里添加(res->values->themes.xml):

<!-- 导航栏透明 -->
<item name="android:navigationBarColor">
    @android:color/transparent
</item>
<!-- 状态栏透明 -->
<item name="android:statusBarColor">
    @android:color/transparent
</item>
<!-- 不要标题栏 -->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>

沉浸式,状态栏高度,刘海屏怎么开启,怎么适配?看这!

何为沉浸式?

沉浸式就是app的头部和状态栏和何为一体的,webview即为整个手机的高度

何为状态栏?

状态栏就是手机顶部,显示时间电量那一行

除此还有刘海屏,水滴屏,挖孔屏,全面屏,非刘海屏,不同手机状态栏高度又不太一样,需要我们去适配,有一个段子说,如果看到那个手机适配有问题,赶紧把那个手机藏起来,不要让测试发现了。

我们用HBuilder创建的应用默认是不开启沉浸式的,需要我们手动如下配置开启。

打开应用的manifest.json文件,切换到代码视图,在plus -> statusbar 下添加immersed节点并设置值为true。

"plus": {
    "statusbar": {
        "immersed": true
    }
}

由于各系统版本的限制,沉浸式状态栏对系统有要求(Android4.4及以上、iOS7.0及以上,这部分手机应该早已淘汰),如果要兼容各系统版本,需要动态判断当前环境是否支持沉浸式状态栏以及系统状态栏的高度:

使用5+API

  • 判断当前环境是否支持沉浸式状态栏
    plus.navigator.isImmersedStatusbar()
    如果当前支持沉浸式状态栏则返回true,否则返回false。
  • 获取当前系统状态栏高度
    plus.navigator.getStatusbarHeight()
    获取系统状态栏高度,Number类型。
    其单位是逻辑像素值,即css中可直接使用的像素值,可能存在小数点

 但是5+API需要在plusready事件后才能调用,通常此事件在DOM加载渲染后才会触发,无法再渲染前根据不同的状态来设置css。所以会导致位置的一个闪动。

为了解决此问题,在支持5+API运行环境的userAgent中特定字段Html5Plus/1.0后添加Immersed标识,如下:
"Html5Plus/1.0 (Immersed/30)"
其中Immersed/后的30表示状态栏的高度,单位为逻辑像素值。

可以使用正则表达式进行获取:

 
var immersed = 0;  
var ms=(/Html5Plus/.+s(.*(Immersed/(d+.?d*).*))/gi).exec(navigator.userAgent);  
if(ms&&ms.length>=3){ // 当前环境为沉浸式状态栏模式  
    immersed=parseFloat(ms[2]);// 获取状态栏的高度  
}

开启了沉浸式,页面就会往上移,头部和状态栏重合,所以我们设置界面头区域的顶部内边距为状态栏的高度

var t=document.getElementById(‘header‘);  
t&&t.style.paddingTop=immersed+‘px‘;

不管是ios还是安卓,不管是刘海屏还是非刘海屏,都不用单独去设置了,在公共js里设置好头部即可。

你学会了吗?赶紧新建一个项目试试吧。

以上是关于Android 全面屏处理(适配挖孔屏刘海屏) kotlin的主要内容,如果未能解决你的问题,请参考以下文章

Android 屏幕适配异形屏适配 ① ( 异形屏类型:刘海屏水滴屏挖孔屏 | 沉浸式布局刘海屏适配 | 华为手机异形屏适配注意点 )

Android 挖孔屏适配

沉浸式,状态栏高度,刘海屏怎么开启,怎么适配?看这!

unity 安卓适配刘海屏,水滴屏,异性屏

如何解决刘海屏

Android刘海屏适配