Android 刘海屏适配总结(推荐)

一、简介

随着 Apple 发布 iPhone X 之后,各大手机厂商也开始模仿这种刘海屏的设计,而且刘海屏手机的用户也是越来越大,前段时间将项目进行了所有主流厂商的刘海屏手机的适配,以便让刘海屏手机的用户也能有更好的体验。

二、刘海屏造成的 UI 显示问题

刘海屏手机因为比平常的手机多了一块顶部的遮挡性刘海,所以会造成顶部 Toolbar 以及搜索框的遮挡,而且有些厂商的手机(vivo、华为),默认是在「无状态栏」的界面将状态栏进行黑化显示,这时候会导致系统下移,从而导致底部的一些 UI 被截断。除此之外,一些控件的显示规则还会受到影响,如 PopupWindow 的显示高度会在「无状态栏」的界面中比普通手机低一个「刘海的高度」,从而遮挡住原先在 PopupWindow 周围的图标。

1、系统下移造成的底部 UI 截断

小说页码被截断

2、刘海挡住标题栏和搜索框

刘海挡住标题栏和搜索框

3、PopupWindow 显示异常

PopupWindow 显示异常

三、通用的适配方案

理论上来讲,通过 Android P 版本提供的刘海屏相关接口,判断手机是否为刘海屏手机,以及进行一些相应的处理是最合适的方式,但现在使用在国内使用 Android P 的接口是不现实的,所以只能通过各大厂商提供的技术文档来进行适配,但适配的流程基本是一致的。

刘海屏的适配流程

刘海屏的适配流程

其中需要着重处理的是:

1、应用是否已经适配刘海屏

2、页面是否显示状态栏

3.1 应用是否已经适配刘海屏

现在国内的主流机型(华为、vivo、OPPO、小米)在刘海屏的显示上分为两个阵营:

  • 当不显示状态栏时,直接将界面进行显示,「状态栏原先的位置也用于显示界面」,例如:OPPO
  • 当不显示状态栏时,直接「将状态栏原先的位置进行黑化,界面整体下移」,例如:华为、vivo

所以,我们在进行刘海屏适配的时候,首先需要通过一些手段,统一各大厂商的显示方案,让所有的刘海屏手机都利用状态栏的界面,「告知系统」我们已经适配了刘海屏,确保系统不会下移我们的应用,保留原生体验。

这里主要有两种方式:

1、设置屏幕高宽比例

因为刘海屏手机的「宽高比」比之前的手机大,如果不适配的话,Android 默认为最大的宽高比为 1.86,

小于刘海屏手机的宽高比,因此我们需要申明更高的宽高比来告诉系统,我们应用已经适配了刘海屏。

只要在 AndroidManifest.xml 中加入如下配置:

<meta-data android:name="android.max_aspect" android:value="2.1"/>

也可以在 Application 添加属性:

android:maxAspectRatio="ratio_float"

ps:这个属性需要 API 26 才支持

2、设置应用支持 resize

我们还可以通过设置应用支持 resizeable,来告诉系统我们适配了刘海屏,而且这也是 Google 官方推荐的方式。不过需要注意的是,使用这个属性之后,应用也会跟着支持分屏模式。只需要在 AndroidManifest.xml 中添加:

android:resizeableActivity="true"

3.2 页面是否显示状态栏

对于刘海屏适配,我们将界面分为两种:

  • 对于有状态栏的界面,不会受到刘海屏的影响
  • 全屏显示的界面(无状态栏),需要根据界面的显示进行一些控件的下移

因此,我们进行刘海屏适配,其实针对的就是没有状态栏的界面,而有状态栏的界面显示是正常的。对于没有状态栏的界面,主要是将对被刘海遮挡到的控件,设置对应刘海高度的 MarginTop,从而避免控件被遮挡。而对于底部可能被截断的界面,可以考虑将底部做成 ScrollView 的形式。

四、各厂商的适配方案

现在 Android P 的接口还没法用,但各手机厂商都制定了自己的 API,对此我们需要对各大机型进行特殊的适配,这里主要介绍 vivo、OPPO、华为 这三种主流手机的适配方案。

华为

华为作为国内的手机厂商大头,自己仿照 Android P 提供的 API,实现了一套几乎差不多的 API,所以我们如果想要告诉系统我们的应用适配了刘海屏,最好直接使用华为的 API,这样才是最保险的。

以下代码来自:华为刘海屏适配官方技术指导

1、应用页面设置使用刘海区显示

① 方案一:在 AndroidManifest.xml 中增加 meta-data 属性,此属性不仅可以针对 Application 生效,也可以对 Activity 配置生效:

<meta-data android:name="android.notch_support" android:value="true"/>

增加这个属性之后,系统就会对应用进行下移处理,从而保证原生体验。

② 方案二:通过添加窗口 FLAG 的方式设置界面使用刘海区:

public static void setFullScreenWindowLayoutInDisplayCutout(Window window) {
   if (window == null) {
     return;
   }
   WindowManager.LayoutParams layoutParams = window.getAttributes();
   try {
     Class layoutParamsExCls = Class.forName("com.huawei.android.view.LayoutParamsEx");
     Constructor con=layoutParamsExCls.getConstructor(LayoutParams.class);
     Object layoutParamsExObj=con.newInstance(layoutParams);
     Method method=layoutParamsExCls.getMethod("addHwFlags", int.class);
     method.invoke(layoutParamsExObj, FLAG_NOTCH_SUPPORT);
   } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |InstantiationException
   | InvocationTargetException e) {
     Log.e("test", "hw add notch screen flag api error");
   } catch (Exception e) {
     Log.e("test", "other Exception");
   }
 }

2、判断该华为手机是否刘海屏

public static boolean hasNotchInHuawei(Context context) {
    boolean hasNotch = false;
    try {
      ClassLoader cl = context.getClassLoader();
      Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
      Method hasNotchInScreen = HwNotchSizeUtil.getMethod("hasNotchInScreen");
      if(hasNotchInScreen != null) {
        hasNotch = (boolean) hasNotchInScreen.invoke(HwNotchSizeUtil);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return hasNotch;
  }

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;
     }

OPPO

OPPO 是主流厂商中的一股清流,学 iPhoneX 是最像的,OPPO 手机对于不显示状态栏的界面,采取的是「状态栏原先的位置也用于显示界面」的方案,所以我们只要进行相关控件的位置移动就可以了。

以下代码来自:OPPO 凹形屏适配说明

1、判断该 OPPO 手机是否为刘海屏手机

public static boolean hasNotchInOppo(Context context) {
    return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
  }

2、获取刘海屏的高度

对于 OPPO 刘海屏手机的刘海高度,OPPO 官方的文档没有提供相关的 API,但官方文档表示 OPPO 手机的刘海高度和状态栏的高度是一致的,而且我也对此进行了验证,确实如此。所以我们可以直接获取状态栏的高度,作为 OPPO 手机的刘海高度。

public static int getStatusBarHeight(Context context) {
  int statusBarHeight = 0;
  int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
  if (resourceId > 0) {
    statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
  }
  return statusBarHeight ;
}

vivo

vivo 提供的技术文档对于开发者来说是最不友好的,只提供了一个 API 来进行刘海屏的判断,并没有提供刘海高度的获取方式,我们只能通过获取状态栏高度来当做刘海的高度,但在某些机型可能会有些偏差。

官方文档: vivo 手机适配指南

判断该 vivo 手机是否为刘海屏手机

public static boolean hasNotchInVivo(Context context) {
    boolean hasNotch = false;
    try {
      ClassLoader cl = context.getClassLoader();
      Class ftFeature = cl.loadClass("android.util.FtFeature");
      Method[] methods = ftFeature.getDeclaredMethods();
      if (methods != null) {
        for (int i = 0; i < methods.length; i++) {
          Method method = methods[i];
          if(method != null) {
            if (method.getName().equalsIgnoreCase("isFeatureSupport")) {
              hasNotch = (boolean) method.invoke(ftFeature, 0x00000020);
              break;
            }
          }
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      hasNotch = false;
    }
    return hasNotch;
  }

五、总结

以上便是在之前在进行 Android 刘海屏适配的时候,所积累的一些经验和心得。将其记录下来,以便自己以后进行回顾,同时也希望这篇文章能对进行刘海屏适配的同学一些帮助。也希望大家多多支持我们。

(0)

相关推荐

  • 简单谈谈我的Android屏幕适配之路

    如果你还在受老板的"这个左移一个像素,再右移两个像素看看,不对不对移回来.这个大了.你没看见吗?这个变形了!"这样的气,那么学完这篇文章,你就可以回他"我已经适配了,你没看粗来吗?" 我们先来了解两个概念:屏幕尺寸和屏幕的分辨率: 屏幕尺寸: 就是屏幕的对角线的长度,度量单位是英寸,1英寸等于2.54厘米. 例如小米5的屏幕尺寸就为5.15英寸.nexus 5的屏幕为4.95英寸. 屏幕分辨率: 实际上就是屏幕横纵坐标上面的像素点.如比较常见的1280×720,19

  • Android中关于屏幕的三个小众知识(宽屏适配、禁止截屏和保持屏幕常亮)

    前言 宽屏适配.禁止截屏和保持屏幕常亮,这三个与屏幕有关的 Android 开发小众知识,说不定什么时候就派上用场. 宽屏适配 Android的屏幕适配一直以来都在折磨着我们Android开发者,越来越多的手机厂商趋向于全面屏设计,比如今年出厂的 18.5:9 屏幕比例的三星 Galaxy S8 手机,前两天刚发布 18:9 屏幕比例的 OnePlus 5T 手机, 屏幕比例均超过过去常见的 16:9 比例.超大屏幕比例的设计对于 Android App 来说,存在一个屏幕适配的问题. 我们需要

  • Android 手机屏幕适配解决办法

    0. 前言 Android的屏幕适配,即使得某一元素在Android不同尺寸.不同分辨率的手机上具备相同的显示效果,这个问题一直以来都是我们Android开发者不得不面对的问题.本文参考了很多前人的博客,并对这一问题做一个总结,力求精简明了. 转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52690498 1. 基础概念 (1)屏幕尺寸,即手机对角线的物理尺寸 1英寸 = 2.54cm  常见手机尺寸有5英寸.5.5英寸.6英寸等

  • Android的分辨率和屏幕适配详解

    一.为什么Android要进行分辨率与屏幕适配 最大的原因是碎片化,因为Android的开源措施和各个厂商的自己细微修改,结果就变成了这个样 需要适配的屏幕尺寸就有这么多: 这怎么可能嘛T_T. 所以我们就只照顾大部分人,根据友盟的统计数据如下: 所以只需要适配: 800x480.854x480.960x540.1184x720.1280x720.1920x1080这六种分辨率. 二.基本知识 屏幕尺寸 英寸,1英寸=2.54厘米.比如常见的屏幕尺寸有2.4.2.8.3.5.3.7.4.2.5.

  • Android-屏幕适配需要注意的地方总结

    1.尽量使用线性布局(LinearLayout)和相对布局(RelativeLayout),不要使用绝对布局. 2.尽量使用dip和sp,不要使用px. 3.为不同的分辨率提供不同的布局文件和图片. 例如:  4.在AndroidMainfest.xml中设置多分辨率支持. 复制代码 代码如下: <supports-screens android:largeScreens="true" android:normalScreens="true" android:

  • Android 图片显示与屏幕适配的问题

    Android 图片显示与屏幕适配的问题 在Android开发中比较头疼的是Android的分辨率问题,那么这里给大家介绍个万能办法,这个办法的优点是可以实现万能适应,给开发和美工设计提供了依据,但是对开发来说代码量也不少,具体办法: (1)获取屏幕的尺寸 WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display d = windowManager.getDefa

  • Android 刘海屏适配总结(推荐)

    一.简介 随着 Apple 发布 iPhone X 之后,各大手机厂商也开始模仿这种刘海屏的设计,而且刘海屏手机的用户也是越来越大,前段时间将项目进行了所有主流厂商的刘海屏手机的适配,以便让刘海屏手机的用户也能有更好的体验. 二.刘海屏造成的 UI 显示问题 刘海屏手机因为比平常的手机多了一块顶部的遮挡性刘海,所以会造成顶部 Toolbar 以及搜索框的遮挡,而且有些厂商的手机(vivo.华为),默认是在「无状态栏」的界面将状态栏进行黑化显示,这时候会导致系统下移,从而导致底部的一些 UI 被截

  • Android刘海屏、水滴屏全面屏适配小结

    现在,市面上的屏幕尺寸和全面屏方案五花八门.这里我使用了小米的图来说明: 上述两种屏幕都可以统称为刘海屏,不过对于右侧较小的刘海,业界一般称为水滴屏或美人尖.为便于说明,后文提到的「刘海屏」「刘海区」都同时指代上图两种屏幕. 刘海屏.水滴屏全面屏适配细节 当我们在谈屏幕适配时,我们具体谈什么呢? 适应更长的屏幕 防止内容被刘海遮挡 其中第一点是所有应用都需要适配的,对应下文的声明最大长宽比,而第二点,如果应用本身不需要全屏显示或使用沉浸式状态栏,是不需要适配的. 针对需要适配第二点的应用,需要获

  • 详解Android 折叠屏适配攻略

    随着三星 Galaxy Fold 和 华为 Mate X 的发布,折叠屏手机开始进入大家的视线.在改变手机体验的同时,也给我们开发人员在适配方面带来了更多的挑战.本文给大家介绍一下 Android 开发中和折叠屏相关的一些概念,以及如何进行折叠屏的适配. 折叠屏适配 折叠屏之所以需要适配,是因为我们的应用有可能在运行的过程中,所在的屏幕尺寸发生了变化,这种情况对现有项目多少都会产生一些问题. 所以折叠屏适配的本质是: 当应用运行时,屏幕的尺寸.密度或比例发生了变化,应用能够继续在变化后的屏幕上正

  • Android全面屏与异形(刘海)屏的适配教程

    写在前面 Android全面屏的手机越来越多了,要开始考虑应用适配全面屏的问题了,查了查相关文章,总结一下. 声明最大屏幕宽高比 以上图片来自Google Developer 通过文档可以看出从Android7.0开始,应用的多窗口模式默认变为启动,在多窗口模式下,默认已经进行了全面屏适配,如果我们不想应用在多窗口模式下运行,可以修改以下属性: android:resizeableActivity="false" 此时,我们可以手动进行设置最大屏幕宽高比: android8.0及以上:

  • 详解Android 华为凹口屏适配小结

    Android8.0以后[凹口屏]得到迅速发展,目前已有了挖孔屏/水滴屏/刘海屏等各式各样的屏幕,究其根本依旧是[凹口屏],单华为一个品牌就涵盖了基本所有类型,而对于屏幕适配也是不可逃避的问题.小菜单独对华为各型号屏幕进行适配尝试,部分方法可通用到其他品牌设备,为 Android 标准 SDK 方法. 其实凹口屏已经出现很久了,对于获取凹口宽高的方式也有很多种,但是以前主流的凹口屏中凹口位置一般是位于屏幕正上方,但随着发展,也出现了在左上角的挖孔屏样式.相应的, Android 9.0 即 SD

  • iphone刘海屏页面适配方法

    1. 下面是实现iphonex 刘海屏前端页面适配的一个插值算法小案例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body, ul { margin: 0; } ul { padding-left: 10px; } li { list-styl

  • Android分屏多窗口的实践代码

    Android N 中推出了多窗口支持,项目要求适配多窗口模式,记录一下. 1.生命周期:对于完全没有适配多窗口的APP来说,当启用多窗口模式或者拖动窗口时,会出现Activity销毁重新加载的现象. 解决方法:在manifest文件里面给activity加上下面一行属性 android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" 2.当启用多窗口模式时,可能有改变原UI的需求,这时可以在

  • 浅析Android录屏 MediaRecorder

    MediaRecorder类介绍: MediaRecorder类是Android sdk提供的一个专门用于音视频录制,一般利用手机麦克风采集音频,摄像头采集图片信息. Android录屏的三种方案 1.adb shell命令screenrecord 2.MediaRecorder, MediaProjection 3.MediaCodec和MediaMuxer, MediaProjection , 一.screenrecord命令 screenrecord是一个shell命令,支持Android

随机推荐