Android 刘海屏和全面屏适配

背景

自从iphone x发布后,各大厂商也发布了类似的刘海屏手机(“顶部屏幕凹槽设计”),开发者应该如何适配呢?

原理

为什么会有刘海屏?

因为大家有自拍的需求,需要摄像头前置,除了摄像头前置外,刘海屏上还有一些其他的传感器,所以不同厂商的刘海屏长度也不相同。


这里主要是介绍一下Android P发布之后刘海屏的适配以及Android P之前的适配。为什么要分开呢?因为Android P之前官方还没提供API来进行适配,都是由各家厂商来提供适配方案的。

2.6 那么刘海屏该如何适配呢?

2.6.1 如果页面存在状态栏

[if !supportLists]· [endif]那么很简单,不用适配,因为刘海区域会包含在状态栏中了。

[if !supportLists]· [endif]如果不想看到刘海区域,可以使用LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER将刘海区域变成一条黑色边。

2.6.2 如果页面是全屏显示

[if !supportLists]· [endif]不适配的话将会留出一条黑色边。

[if !supportLists]· [endif]要做到真正全屏的话,那么就先要获取到刘海的区域(危险区域),内容部分(操作按钮等)应当避开危险区域,保证在安全区域中展示。横屏的话两边都需要注意避开刘海(危险区域)。



华为适配刘海屏主要有以下几个步骤: 1.配置meta-data 

[if !supportLists]2. [endif]检测是否存在刘海屏3.获取刘海屏的参数4. UI适配

 

 

 

 

1.配置meta-data 华为新增的Meta-data属性android.notch_support在应用的AndroidManifest.xml中增加meta-data属性,此属性不仅可以针对Application生效,也可以对Activity配置生效,具体方式如下所示:

[if !supportLists]· [endif]1

①对Application生效,意味着该应用的所有页面,(会对你App的所有页面都进行适配)系统都不会做竖屏场景的特殊下移或者是横屏场景的右移特殊处理:

 ② 对Activity生效,意味着可以针对单个页面进行刘海屏适配,设置了该属性的Activity系统将不会做特殊处理: 


2.检测是否存在刘海屏

public static boolean hasNotchInScreen(Context context) {

   boolean ret = false;

   try {

       ClassLoader cl = context.getClassLoader();

       Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");

       Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");

       ret = (boolean) get.invoke(HwNotchSizeUtil);

   } catch (ClassNotFoundException e) {

       Log.e("test", "hasNotchInScreen ClassNotFoundException");

   } catch (NoSuchMethodException e) {

       Log.e("test", "hasNotchInScreen NoSuchMethodException");

   } catch (Exception e) {

       Log.e("test", "hasNotchInScreen Exception");

   } finally {

       return ret;

   }

}

 

 

3.获取刘海屏的参数

public static int[] getNotchSize(Context context) {

   int[] ret = new int[]{0, 0};

   try {

       ClassLoader cl = context.getClassLoader();

       Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");

       Method get = HwNotchSizeUtil.getMethod("getNotchSize");

       ret = (int[]) get.invoke(HwNotchSizeUtil);

   } catch (ClassNotFoundException e) {

       Log.e("test", "getNotchSize ClassNotFoundException");

   } catch (NoSuchMethodException e) {

       Log.e("test", "getNotchSize NoSuchMethodException");

   } catch (Exception e) {

       Log.e("test", "getNotchSize Exception");

   } finally {

       return ret;

   }

}

 

4. UI适配 通过增加上面适配方案提到的配置(meta-data或者是Flag),应用在华为刘海屏手机上就能够默认使用刘海区显示了,但是为了避免出现UI被刘海区遮挡的问题,还是需要应用自己做一些额外的UI适配工作:(1)判断是否刘海屏,通过华为刘海屏SDK的API判断,具体参考3.2.1章节(2)如果是刘海屏手机需要应用自己调整布局避开刘海区,布局原则:保证重要的文字、图片和视频信息、可点击的控件和图标还有应用弹窗等等布局建议显示在状态栏区域以下(安全区域);不重要,遮挡不会出现问题的布局可以延伸到状态栏区域(危险区域)显示,按照这种布局原则修改,可以一次修改就能适配所有的刘海屏手机:


获取系统状态栏高度接口:

public static int getStatusBarHeight(Context context) {

    int result = 0;

    int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");

    if (resourceId > 0) {

        result = context.getResources().getDimensionPixelSize(resourceId);

    }

    return result;

}

 

 

vivo & OPPO

vivo 和 OPPO官网仅仅给出了适配指导,没有给出具体方案,简单总结为: 如有是具有刘海屏的手机,竖屏显示状态栏,横屏不要在危险区显示重要信息或者设置点击事件。

首先,判断是不是刘海屏手机。OPPO判断方法:

public static boolean hasNotchInOppo(Context context){

   return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");

}



vivo的判断方法:

public static final int NOTCH_IN_SCREEN_VOIO=0x00000020;//是否有凹槽public static final int ROUNDED_IN_SCREEN_VOIO=0x00000008;//是否有圆角public static boolean hasNotchInScreenAtVoio(Context context){

   boolean ret = false;

   try {

       ClassLoader cl = context.getClassLoader();

       Class FtFeature = cl.loadClass("com.util.FtFeature");

       Method get = FtFeature.getMethod("isFeatureSupport",int.class);

       ret = (boolean) get.invoke(FtFeature,NOTCH_IN_SCREEN_VOIO);


   } catch (ClassNotFoundException e)

   { Log.e("test", "hasNotchInScreen ClassNotFoundException"); }

   catch (NoSuchMethodException e)

   { Log.e("test", "hasNotchInScreen NoSuchMethodException"); }

   catch (Exception e)

   { Log.e("test", "hasNotchInScreen Exception"); }

   finally

   { return ret; }

}

然后在进行适配,官方这方面的资料很少也不是很详细

 

google官方

google从Android P开始为刘海屏提供支持,目前提供了一个类和三种模式: 一个类指的是可以用DisplayCutout这个类找出刘海(cutout)的位置和形状,调用getDisplayCutout()这个方法可以获取刘海(cut

out)的位置和区域。

3.1 开启刘海屏

我们在全屏的页面,需要单独开启支持刘海屏。而Google 提供的适配方案,可以设置是否在全屏模式下,使用刘海屏的区域。

WindowManager.LayoutParams lp

                =getWindow().getAttributes();

lp.layoutInDisplayCutoutMode =

                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;

getWindow().setAttributes(lp);

新的布局属性layoutInDisplayCutoutMode 包含三种可选的模式,

模式模式说明 

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT只有当DisplayCutout完全包含在系统栏中时,才允许窗口延伸到DisplayCutout区域。 否则,窗口布局不与DisplayCutout区域重叠。 

LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER该窗口决不允许与DisplayCutout区域重叠。 

LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES该窗口始终允许延伸到屏幕短边上的DisplayCutout区域。 

[if !supportLists]1. [endif]LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES模式会让屏幕到延申刘海区域中。

[if !supportLists]2. [endif]LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER模式不会让屏幕到延申刘海区域中,会留出一片黑色区域。

[if !supportLists]3. [endif]LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT模式在全屏显示下跟LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER一样。

这里设置为全屏的显示效果,三种模式的结果如下图所示


[if !supportLists]1. [endif]LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES模式会让屏幕到延申刘海区域中。

[if !supportLists]2. [endif]LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER模式不会让屏幕到延申刘海区域中,会留出一片黑色区域。

[if !supportLists]3. [endif]LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT模式在全屏显示下跟LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER一样。




LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT模式在沉浸式状态栏下的效果:



3.2 刘海屏的高度

在全屏模式下,我们需要有办法获取到刘海屏凹槽的高度,才可以做到设计和布局的时候,留出安全距离。

虽然Google 要求,刘海屏的凹槽,必须和刘海的高度保持一致,而刘海屏又被隐藏在状态栏了,所以有一个思路是直接获取状态栏的高度,来判断刘海之外,可布局的安全区域。

不过Android P 已经预留出了标准的测量 刘海屏凹槽 的 Api:DisplayCutout。

刘海屏的凹槽,就在屏幕的中间,所以只有getSafeInsetTop() 方法返回的结果


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容