美文网首页安卓
[非完美解决]Toast在刘海屏上显示时顶部高度问题总结

[非完美解决]Toast在刘海屏上显示时顶部高度问题总结

作者: kongzue | 来源:发表于2019-11-09 20:53 被阅读0次

问题描述

DialogV3 库在普通设备上也是做了沉浸式适配的,但在正常屏幕上呈现时会自动设置一段顶部距离以隔出状态栏位置,防止叠加造成视觉观感下降,如下图所示:


普通设备.png

但在刘海屏设备上,却发现系统额外的加入了一段刘海区域高度,呈现方式如图:


刘海屏呈现问题.png

明显能看得出来是系统在布局外部额外加了一个状态栏(刘海)高度导致本来全屏的Toast被向下移动了一定高度,

验证过程

最初猜测是系统在底布局加入了安全区,即WindowInsets,安全区会在设置安全区的布局上设置padding以实现对顶部状态栏高度和底部导航栏高度的隔离,尝试对view.getRootView设置背景颜色为红色,看运行情况,验证是否为安全区,代码如下:

toast.getView().getRootView().setBackgroundColor(Color.RED);

运行结果出乎意料,根布局是外部被挤下去的一段距离,如果是安全区的话肯定是padding而不是类似下图的margin,证明不是安全区的问题,如图:


安全区验证.png

解决方案

经过多次尝试,无法去掉这段距离,那么解决方案改为了将自身padding的距离取消掉以实现正常显示,具体做法如下:

private int getStatusBarHeight() {
    if (context.get() instanceof  Activity){
        Activity activity = (Activity) context.get();
        boolean isHasNotch = NotchUtil.hasNotchInScreen(activity);
        if (isHasNotch){
            return 0;
        }
    }
    //其他代码...
}

判断当存在刘海时设置paddingTop所需要的状态栏高度为0,兼容性解决此问题,效果如下:

兼容性解决.png
上述代码中的NotchUtil代码如下,因不同品牌手机刘海屏判断方式不一样,直接使用了来自耳东_
的博客https://blog.csdn.net/u011494285/article/details/86681405 代码,感谢他的开源贡献:
public class NotchUtil {
    
    /**
     * 是否有刘海屏
     *
     * @return
     */
    public static boolean hasNotchInScreen(Activity activity) {
        
        // android  P 以上有标准 API 来判断是否有刘海屏
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            DisplayCutout displayCutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
            if (displayCutout != null) {
                // 说明有刘海屏
                return true;
            }
        } else {
            // 通过其他方式判断是否有刘海屏  目前官方提供有开发文档的就 小米,vivo,华为(荣耀),oppo
            String manufacturer = Build.MANUFACTURER;
            
            if (isEmpty(manufacturer)) {
                return false;
            } else if (manufacturer.equalsIgnoreCase("HUAWEI")) {
                return hasNotchHw(activity);
            } else if (manufacturer.equalsIgnoreCase("xiaomi")) {
                return hasNotchXiaoMi(activity);
            } else if (manufacturer.equalsIgnoreCase("oppo")) {
                return hasNotchOPPO(activity);
            } else if (manufacturer.equalsIgnoreCase("vivo")) {
                return hasNotchVIVO(activity);
            } else {
                return false;
            }
        }
        return false;
    }
    
    /**
     * 判断vivo是否有刘海屏
     * https://swsdl.vivo.com.cn/appstore/developer/uploadfile/20180328/20180328152252602.pdf
     *
     * @param activity
     * @return
     */
    private static boolean hasNotchVIVO(Activity activity) {
        try {
            Class<?> c = Class.forName("android.util.FtFeature");
            Method get = c.getMethod("isFeatureSupport", int.class);
            return (boolean) (get.invoke(c, 0x20));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    /**
     * 判断oppo是否有刘海屏
     * https://open.oppomobile.com/wiki/doc#id=10159
     *
     * @param activity
     * @return
     */
    private static boolean hasNotchOPPO(Activity activity) {
        return activity.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
    }
    
    /**
     * 判断xiaomi是否有刘海屏
     * https://dev.mi.com/console/doc/detail?pId=1293
     *
     * @param activity
     * @return
     */
    private static boolean hasNotchXiaoMi(Activity activity) {
        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("getInt", String.class, int.class);
            return (int) (get.invoke(c, "ro.miui.notch", 0)) == 1;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    
    /**
     * 判断华为是否有刘海屏
     * https://devcenter-test.huawei.com/consumer/cn/devservice/doc/50114
     *
     * @param activity
     * @return
     */
    private static boolean hasNotchHw(Activity activity) {
        
        try {
            ClassLoader cl = activity.getClassLoader();
            Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
            return (boolean) get.invoke(HwNotchSizeUtil);
        } catch (Exception e) {
            return false;
        }
    }
}

目前的方案并不完美,如果有更好的方案我会在第一时间更新解决。

相关文章

网友评论

    本文标题:[非完美解决]Toast在刘海屏上显示时顶部高度问题总结

    本文链接:https://www.haomeiwen.com/subject/cvnnbctx.html