Android适配刘海屏

前言

公司最近要适配华为Pro20,没办法 – 。–

一、AndroidP的适配方案

上来我最先找到的就是AndroidP,就先以这个入手了。 
首先看下谷歌给出的api,大致就分为两种。 
1.设置全屏模式

WindowManager.LayoutParams lp
                =getWindow().getAttributes();
lp.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
getWindow().setAttributes(lp);

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

public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;

2.获取刘海屏

view.postDelayed(new Runnable() {
    @Override
    public void run() {
        DisplayCutout displayCutout = view.getRootWindowInsets().getDisplayCutout();
        Log.i("cxmyDev", "SafeInsetBottom:" + displayCutout.getSafeInsetBottom());
        Log.i("cxmyDev", "SafeInsetLeft:" + displayCutout.getSafeInsetLeft());
        Log.i("cxmyDev", "SafeInsetRight:" + displayCutout.getSafeInsetRight());
        Log.i("cxmyDev", "SafeInsetTop:" + displayCutout.getSafeInsetTop());
    }
}, 100);

刘海屏的凹槽,就在屏幕的中间,所以只有 getSafeInsetTop() 方法返回的结果,是我们需要的,而其他的 getSafeInsetXxx() 方法,直接返回的是 0 。

这里有人说了,没有华为Pro20怎么办?当然不能买一个!那多费钱,我们可以下载模拟器。 
在模拟器中,可以通过开发者选项里的 “Simulate a display with a cutout”,开启刘海屏的支持。

这里写图片描述

你们以为解决了么,遗憾的告诉你们并没有。 
你们看下我写到程序的代码如下:

    Util.logv("Util", "SDK_INT:" + Build.VERSION.SDK_INT);

        DisplayCutout displayCutout = null;
        if (Build.VERSION.SDK_INT >= 28) {
            displayCutout = new View(this).getRootWindowInsets().getDisplayCutout();
            Util.logv("Util", "SafeInsetBottom:" + displayCutout.getSafeInsetBottom());
            Util.logv("Util", "SafeInsetLeft:" + displayCutout.getSafeInsetLeft());
            Util.logv("Util", "SafeInsetRight:" + displayCutout.getSafeInsetRight());
            Util.logv("Util", "SafeInsetTop:" + displayCutout.getSafeInsetTop());
        }

可以看出SDK_INT >=28 才会走DisplayCutout 的相关方法,而上面我打的log显示的SDK_INT =27这根本走不通。起初我以为是模拟器的问题,于是我是华为的平台上用远程真机Pro20测试,发现SDK_INT 也是等于27,于是此路不通。 
原因估计如下:

1O版本适配:谷歌未提供统一方案,需要使用华为提供的刘海屏SDK进行适配,同时华为刘海屏SDK方案
也会继承到华为P版本,在华为P版本中将同时支持两种方案:华为O版本方案+谷歌P版本方案;
(2)P版本适配:谷歌已经提供统一的适配方案,建议应用采用谷歌统一的方案进行适配。

也就是说不能用谷歌的api解决华为Pro20的问题。

二、手机厂商的适配API

第一条路不通,于是我改变思路,这次是适配华为Pro20 ,既然谷歌不可以,那么华为有没给对应的适配方案呢?不出我们所料是有的,我还顺便找了VOIO和oppod的。

华为:
http://mini.eastday.com/bdmip/180411011257629.html
oppo:
https://open.oppomobile.com/wiki/doc#id=10139
voio:
https://dev.vivo.com.cn/doc/document/info?id=103

实现原理都是一样的利用反射调用对应的api方法。 
代码都给你写好了,≡(▔﹏▔)≡

/**
*华为start
*/
//判断是否是华为刘海屏
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; }
}
//获取华为刘海的高宽
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; }
}
//全屏显示 暂时不能用
public static final int FLAG_NOTCH_SUPPORT=0x00010000;
@TargetApi(Build.VERSION_CODES.KITKAT)
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(WindowManager.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 notch screen flag api error"); }
    catch (Exception e) { Log.e("test", "other Exception"); }
}
/**
*华为end
*/

/**
*Oppo start
*/
public static boolean hasNotchInScreenAtOppo(Context context){
    return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
}
/**
*Oppo end
*/

/**
*voio start
*/
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; }
}
/**
*voio end
*/

具体使用,就看你们的具体需求了。

总结:不要死钻牛角尖,试试换个思路。


终于找到一个能用的,我先去开开荤

猜你喜欢

转载自blog.csdn.net/sinat_29874521/article/details/80224447