基于安卓9.0对于刘海屏的适配做下简单的总结,当前前提是应用是沉浸式的体验效果,如果无需做到沉浸式的体验效果,则可忽略,因为一般情况下刘海的区域和高度刚好和系统导航栏一样高,可以不考虑刘海,本片主要整理沉浸式体验的刘海屏适配梳理。
1.设置全屏
代码很简单,放在setContentView之前就行,运行后导航栏不显示,然后内容区域也不会到刘海区域,没有刘海的手机默认就到屏幕顶部了,这里的模拟器有刘海。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//1.设置全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
Window window = getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
}
2.判断手机是否刘海
判断手机是否支出刘海定义到一个方法
private boolean hasDisplayCutout(Window window) {
DisplayCutout displayCutout;
View rootView = window.getDecorView();
WindowInsets insets = rootView.getRootWindowInsets();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && insets != null){
displayCutout = insets.getDisplayCutout();
if (displayCutout != null){
if (displayCutout.getBoundingRects() != null && displayCutout.getBoundingRects().size() > 0 && displayCutout.getSafeInsetTop() > 0){
return true;
}
}
}
return false; //模拟器可能会出现异常,真机不会
}
3.设置是否让内容区域延伸进刘海及是否设置成沉浸式
对于刘海屏我们将内容延伸进刘海区域,并且设置成沉浸式
//3.设置是否让内容区域延伸进刘海及是否设置成沉浸式
if (isDisplayCutout){//让内容区域延伸进刘海
WindowManager.LayoutParams params = window.getAttributes();
/**
* * @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.setAttributes(params);
//设置成沉浸式
int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
int visibility = window.getDecorView().getSystemUiVisibility();
visibility |= flags; //追加沉浸式设置
window.getDecorView().setSystemUiVisibility(visibility);
}
至此刘海屏的适配就完成了,内容已经延伸到了刘海里面。
4.设置控件是否避开刘海区域
适配完成之后,如果我们有一个控件在顶部的时候可能会出现尴尬的被刘海切掉。
因此需要对控件是否避开刘海区域做规避,一般情况下刘海的高度就是状态栏的高度,我们简单处理的话可以按照状态栏的高度去处理,追求极致的话可以看看每一家手机厂商官网的sdk介绍,然后区分厂商适配。原则就是我们判断下,如果是刘海屏,对控件设置一个向上的margin值或者对其父控件设置一个paddingTop的值,这个值就是刘海的高度。
获取刘海的高度:
public int heightForDisplayCutout(){
int resID = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resID > 0){
return getResources().getDimensionPixelSize(resID);
}
return 96;
}
对控件设置margin值,感兴趣的也可以对其父控件设置padding值,这里就不做演示了:
View view = findViewById(R.id.view);
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
params.topMargin = heightForDisplayCutout();
view.setLayoutParams(params);
至此整个刘海屏适配完成。附上完整代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//1.设置全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
Window window = getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//2.判断手机是否刘海
boolean isDisplayCutout = isDisplayCutout(window);
//3.设置是否让内容区域延伸进刘海及是否设置成沉浸式
if (isDisplayCutout) {//让内容区域延伸进刘海
WindowManager.LayoutParams params = window.getAttributes();
/**
* * @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.setAttributes(params);
//设置成沉浸式
int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
int visibility = window.getDecorView().getSystemUiVisibility();
visibility |= flags; //追加沉浸式设置
window.getDecorView().setSystemUiVisibility(visibility);
}
setContentView(R.layout.activity_main);
View view = findViewById(R.id.view);
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
params.topMargin = heightForDisplayCutout();
view.setLayoutParams(params);
}
private boolean isDisplayCutout(Window window) {
DisplayCutout displayCutout;
View rootView = window.getDecorView();
WindowInsets insets = rootView.getRootWindowInsets();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && insets != null) {
displayCutout = insets.getDisplayCutout();
if (displayCutout != null) {
if (displayCutout.getBoundingRects() != null && displayCutout.getBoundingRects().size() > 0 && displayCutout.getSafeInsetTop() > 0) {
return true;
}
}
}
return false; //模拟器可能获取失败,模拟器演示时将此处改为true看效果
}
//通常情况下,刘海的高就是状态栏的高
public int heightForDisplayCutout() {
int resID = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resID > 0) {
return getResources().getDimensionPixelSize(resID);
}
return 96;
}
}