Android刘海屏适配

刘海屏和水滴屏的手机目前市场上还是挺多的,所以如果有必要的话,我们开发者还是需要去适配一下。

那什么情况下我们需要去适配这个刘海屏呢?

  1. 如果App使用了沉浸式的状态栏,或者透明状态栏,我们自己的布局延伸到了状态栏内部,这时候如果我们在刘海处有一个可交互的控件就会被遮挡
  2. 使用了全面屏的页面,比如APP的闪屏界面,图片查看大图的页面,这时候状态栏不可见,刘海会遮挡一部分地方。

如果没有上面两种情况,可以不去适配刘海屏。Android从9.0开始加入刘海屏适配的API,9.0之前的刘海屏手机想要适配就得去各个厂商的官网去找适配的代码了。

Anroid9.0官方适配的原则

  1. 如果不是全屏模式(有状态栏)则不受刘海屏的影响。因为刘海屏的高度一般就是状态栏的高度
  2. 对于全屏显示的界面,如果没有适配刘海屏,系统会有一个默认的下移处理来避开刘海屏,竖屏向下移动,横屏想右移动。
  3. 想要真正的全屏显示,需要通过Android9.0提供的API进行适配处理。

所以说,如果遇到》=9.0的Android刘海屏手机,如果没有适配刘海,我们设置的全屏的界面默认不是全屏的,会避开刘海区域。

那如果设置了全屏或者沉浸栏,如何让内容延伸进状态栏呢,需要调用几个新的API,下面的API只有targetSdkVersion 28以上才能找到,先判断是否有刘海

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 判断是否有刘海
*/
@TargetApi(28)
private fun hasDisplayCutout(window: Window): Boolean {
val displayCutout: DisplayCutout?
val rootView = window.decorView
val insets = rootView.rootWindowInsets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && insets != null) {
displayCutout = insets.displayCutout
if (displayCutout != null) {
if (displayCutout.boundingRects != null && displayCutout.boundingRects.size > 0 && displayCutout.safeInsetTop > 0) {
return true
}
}
}
return false
}

然后允许内容延伸进刘海区域其实也就是状态栏

1
2
3
4
5
6
7
8
9
10
11
if(hasDisplayCutout(window)){
//2.让内容区域延伸进刘海
val params = window.attributes
/**
* * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 全屏模式,内容下移,非全屏不受影响
* * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 允许内容去延伸进刘海区
* * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 不允许内容延伸进刘海区
*/
params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
window.attributes = params
}

OK 内容延伸到状态栏中了,如果我们界面顶部有一个可交互的控件,比如很多APP在顶部设置一个全局的搜索框,这就会被刘海遮盖住了。解决方法很简单

1.设计的时候避开这个区域

2.给该控件一个顶部的margin值或者给它的父控件一个padding值,这个值可以直接拿状态栏的高度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

//1.设置全屏
requestWindowFeature(Window.FEATURE_NO_TITLE)
val window = window
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)

setContentView(R.layout.activity_bang)
root_view.setPadding(0,getStatusBarHeight(this),0,0)

}
/**
* 获取状态栏高度
*
* @param context
* @return
*/
fun getStatusBarHeight(context: Context): Int {
var statusBarHeight = 0
val resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
statusBarHeight = context.getResources().getDimensionPixelSize(resourceId)
}
return statusBarHeight
}

3.在布局文件的根布局加一个属性android:fitsSystemWindows=”true”,就会自动往下移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/root_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/loading"
android:fitsSystemWindows="true"
>
<EditText
android:layout_width="200dp"
android:layout_height="40dp"
android:layout_centerHorizontal="true"
android:text="请输入"
android:background="@drawable/selector_button"
/>
</RelativeLayout>

对于国内的一些手机厂商的适配,8.0,9.0的手机都有,需要去其官网看看其文档,然后根据不同的机型调用不同厂商的API。

优先使用厂商的API,即使是9.0的手机,厂商没有对应API的时候在使用谷歌提供的9.0以上的适配方式

判断是那个厂商使用可以使用布兰柯基大佬的util

华为:https://devcenter.huawei.com/consumer/cn/devservice/doc/50114

小米:https://dev.mi.com/console/doc/detail?pId=1293

Oppo:https://open.oppomobile.com/service/message/detail?id=61876

Vivo:https://dev.vivo.com.cn/documentCenter/doc/103

# UI

コメント

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×