[非完美解决]Toast在刘海屏上显示时顶部高度问题总结
2019-11-09 本文已影响0人
kongzue
问题描述
DialogV3 库在普通设备上也是做了沉浸式适配的,但在正常屏幕上呈现时会自动设置一段顶部距离以隔出状态栏位置,防止叠加造成视觉观感下降,如下图所示:
![](https://img.haomeiwen.com/i1976622/4931ff04017ae402.png)
但在刘海屏设备上,却发现系统额外的加入了一段刘海区域高度,呈现方式如图:
![](https://img.haomeiwen.com/i1976622/0e2fbab20a9fcec6.png)
明显能看得出来是系统在布局外部额外加了一个状态栏(刘海)高度导致本来全屏的Toast被向下移动了一定高度,
验证过程
最初猜测是系统在底布局加入了安全区,即WindowInsets,安全区会在设置安全区的布局上设置padding以实现对顶部状态栏高度和底部导航栏高度的隔离,尝试对view.getRootView设置背景颜色为红色,看运行情况,验证是否为安全区,代码如下:
toast.getView().getRootView().setBackgroundColor(Color.RED);
运行结果出乎意料,根布局是外部被挤下去的一段距离,如果是安全区的话肯定是padding而不是类似下图的margin,证明不是安全区的问题,如图:
![](https://img.haomeiwen.com/i1976622/f43975703bc7193a.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,兼容性解决此问题,效果如下:
![](https://img.haomeiwen.com/i1976622/afa5386f8965c213.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;
}
}
}
目前的方案并不完美,如果有更好的方案我会在第一时间更新解决。