Android 华为凹口屏适配小结
Android8.0 以后【凹口屏】得到迅速发展,目前已有了挖孔屏/水滴屏/刘海屏等各式各样的屏幕,究其根本依旧是【凹口屏】,单华为一个品牌就涵盖了基本所有类型,而对于屏幕适配也是不可逃避的问题。小菜单独对华为各型号屏幕进行适配尝试,部分方法可通用到其他品牌设备,为 Android 标准 SDK 方法。
其实凹口屏已经出现很久了,对于获取凹口宽高的方式也有很多种,但是以前主流的凹口屏中凹口位置一般是位于屏幕正上方,但随着发展,也出现了在左上角的挖孔屏样式。相应的,Android 9.0 即 SDK28 也发布了获取凹口屏的方法。
Android 9.0 以下适配方案
对华为设备凹口屏适配情况来说,若仅需获取凹口位置的宽高,如下方法即可,在 Android 各版本中均可(Android 9.0 及以上亦可)。此时获取屏幕水平方向安全位置时,可根据屏幕宽度-凹口宽度再左右均分即可。
/**
* 华为凹口屏判断方法 Android 各版本均可
* @param context
* @return
*/
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(TAG, "hasNotchInScreen ClassNotFoundException");
} catch (NoSuchMethodException e) {
Log.e(TAG, "hasNotchInScreen NoSuchMethodException");
} catch (Exception e) {
Log.e(TAG, "hasNotchInScreen Exception");
} finally {
return ret;
}
}
/**
* 华为凹口屏宽高获取方式 int[]{width, height}
* @param context
* @return
*/
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(TAG, "getNotchSize ClassNotFoundException");
} catch (NoSuchMethodException e) {
Log.e(TAG, "getNotchSize NoSuchMethodException");
} catch (Exception e) {
Log.e(TAG, "getNotchSize Exception");
} finally {
notchWidth = ret[0];
notchHeight = ret[1];
return ret;
}
}
Android 9.0 及以上适配
对于华为新出的挖孔屏设备基本均为 Android 9.0 及以上,Android 9.0 提供了对凹口屏相关的 SDK,谷歌认为凹口位置可以不固定位置也不固定个数,但是对于设备一条边只能有一个;如下方法对于 Android 9.0 及以上设备判断均可。SDK 不仅可以判断是否为凹口屏,同时可以获取各个凹口大小及所在位置。
步骤如下:
- 升级 build.gradle 中 compileSdkVersion 或 targetSdkVersion 为 28;
- 在 Application 或 Activity 中设置 meta-data 属性,小菜测试不设置亦可;
<meta-data android:name="android.notch_support" android:value="true"/>
- 根据如下方法获取相应参数;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
getSupportActionBar().hide();
getWindow().getDecorView()
.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
//设置页面全屏显示
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
//设置页面延伸到凹口区显示
getWindow().setAttributes(lp);
getWindow().getDecorView()
.findViewById(android.R.id.content)
.getRootView()
.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
@Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
DisplayCutout cutout = windowInsets.getDisplayCutout();
if (cutout == null) {
Log.e(TAG, "cutout==null, is not notch screen");//通过cutout是否为null判断是否凹口手机
isNotchScreen = false;
} else {
List<Rect> rects = cutout.getBoundingRects();
if (rects == null || rects.size() == 0) {
Log.e(TAG, "rects==null || rects.size()==0, is not notch screen");
isNotchScreen = true;
} else {
Log.e(TAG, "rect size:" + rects.size());//注意:凹口的数量可以是多个
isNotchScreen = true;
for (Rect rect : rects) {
notchRight = rect.right;
notchLeft = rect.left;
notchTop = rect.top;
notchBottom = rect.bottom;
notchWidth = notchRight - notchLeft;
notchHeight = notchBottom - notchLeft;
safeLeft = cutout.getSafeInsetLeft();
safeRight = cutout.getSafeInsetRight();
safeTop = cutout.getSafeInsetTop();
safeBottom = cutout.getSafeInsetBottom();
}
}
}
return windowInsets;
}
});
}
注意事项:
- 小菜在设置 Application 或 Activity 的主题为 NoActionBar 样式,此时要去掉 getSupportActionBar().hide(); 否则会报空指针异常;
<style name="NoBarTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
- 如下设置全屏使用凹口屏时要注意 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,否则参数很有可能获取不到;
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(lp);
- 设置主题 NoActionBar 或代码中动态设置 getSupportActionBar().hide(); 展示效果在 Android 9.0 以下有部分差异,如下:
对于凹口屏适配还有很多机型要单独处理,以上仅对华为设备进行参考;如果有不对的地方还希望多多指出。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
3.2019Android View总结
1.View的滑动方式 a.layout(left,top,right,bottom):通过修改View四个方向的属性值来修改View的坐标,从而滑动Viewb.offsetLeftAndRight() offsetTopAndBottom():指定偏移量滑动viewc.LayoutParams,改变布局参数:layoutParams中保存了view的布局参数,可以通过修改布局参数的方式滑动viewd.通过动画来移动view:注意安卓的平移动画不能改变view的位置参数,属性动画可以e.scrollTo/scrollBy:注意移动的是view的内容,scrollBy(50,50)你会看到屏幕上的内容向屏幕的左上角移动了,这是参考对象不同导致的,你可以看作是它移动的是手机屏幕,手机屏幕向右下角移动,那么屏幕上的内容就像左上角移动了f.scroller:scroller需要配置computeScroll方法实现view的滑动,scroller本身并不会滑动view,它的作用可以看作一个插值器,它会计算当前时间点view应该滑动到的距离,然后view不断的重绘,不断的调用computeScr...
-
下一篇
移动端H5中JS调用原生接口的原理总结(JSBridge)
JS调用android接口的原理: 1. H5中的JS发起请求,在android的WebViewClient.shouldOverrideUrlLoading方法中拦截URL请求,判断是否为接口调用 2. android通过webView.addJavascriptInterface方法向windows对象中注入原生代码,然后H5在JS中调用相应的方法 3.选择prompt,console.log,alert等方法作为通信的接口 JS调用IOS接口的原理 UIWebView的delegate函数拦截jsbridge://开头的请求
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2全家桶,快速入门学习开发网站教程
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- MySQL8.0.19开启GTID主从同步CentOS8
- MySQL数据库在高并发下的优化方案