Android 浅谈适配全面屏、刘海屏、水滴屏

news/2024/10/16 19:25:36/

对刘海屏、水滴屏做适配前,先在此给出一个基本概念:何谓刘海屏?何谓水滴屏?

上述两种屏幕都可以统称为刘海屏,不过对于右侧较小的刘海,业界一般称为水滴屏或美人尖。

目前国内流行的手机厂商主要有:vivo、oppo、华为、小米。各厂商对刘海屏的适配都大不相同,各自有各自对刘海屏的适配API,具体的适配方法可以阅读相应的官网:

VIVO:https://dev.vivo.com.cn/documentCenter/doc/103

OPPO:https://open.oppomobile.com/wiki/doc#id=10159

小米:https://dev.mi.com/console/doc/detail?pId=1293

华为:https://developer.huawei.com/consumer/cn/devservice/doc/50114?from=timeline

具体的适配方法这里不作一一介绍,按照以上四大厂商官网所给出的适配方法,这里给出四大厂商判断/获取刘海屏的工具类:

/*** xiaomi、huawei、vivo、oppo流行机型异型屏判断工具类*/
public class NotchScreenTool {//刘海屏、水滴屏等异型屏支持的Android系统版本:8.0-》全面屏  8.0以上-》刘海屏、水滴屏等异型屏public static boolean isNotchSupportVersion(){int curApiVersion = Build.VERSION.SDK_INT;if(curApiVersion > 26){return true;}return false;}//获取手机屏幕的旋转角度public static int getScreenAngle(Context context){return ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();}//检查流行机型是否存在刘海屏public static boolean isNotch(Context context){return isNotch_VIVO(context) || isNotch_OPPO(context) || isNotch_HUAWEI(context) || isNotch_XIAOMI(context);}//检查vivo是否存在刘海屏、水滴屏等异型屏public static boolean isNotch_VIVO(Context context){boolean isNotch = false;try {ClassLoader cl = context.getClassLoader();Class cls = cl.loadClass("android.util.FtFeature");Method method = cls.getMethod("isFeatureSupport", int.class);isNotch = (boolean) method.invoke(cls,0x00000020);//0x00000020:是否有刘海  0x00000008:是否有圆角} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}finally {return isNotch;}}//检查oppo是否存在刘海屏、水滴屏等异型屏public static boolean isNotch_OPPO(Context context){boolean isNotch = false;try {isNotch = context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");}catch (Exception e){e.printStackTrace();}finally {return isNotch;}}//检查huawei是否存在刘海屏、水滴屏等异型屏public static boolean isNotch_HUAWEI(Context context) {boolean isNotch = false;try {ClassLoader cl = context.getClassLoader();Class cls = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");Method method = cls.getMethod("hasNotchInScreen");isNotch = (boolean) method.invoke(cls);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();} finally {return isNotch;}}//检查xiaomi是否存在刘海屏、水滴屏等异型屏public static boolean isNotch_XIAOMI(Context context){boolean isNotch = false;try {ClassLoader cl = context.getClassLoader();Class cls = cl.loadClass("android.os.SystemProperties");Method method = cls.getMethod("getInt", String.class, int.class);isNotch = ((int) method.invoke(null, "ro.miui.notch", 0) == 1);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}finally {return isNotch;}}//获取huawei刘海屏、水滴屏的宽度和高度:int[0]值为刘海宽度 int[1]值为刘海高度public static int[] getNotchSize_HUAWEI(Context context) {int[] notchSize = new int[]{0, 0};try {ClassLoader cl = context.getClassLoader();Class cls = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");Method method = cls.getMethod("getNotchSize");notchSize = (int[]) method.invoke(cls);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();} finally {return notchSize;}}//获取xiaomi刘海屏、水滴屏的宽度和高度:int[0]值为刘海宽度 int[1]值为刘海高度public static int[] getNotchSize_XIAOMI(Context context){int[] notchSize = new int[]{0,0};if(isNotch_XIAOMI(context)) {int resourceWidthId = context.getResources().getIdentifier("notch_width", "dimen", "android");if (resourceWidthId > 0) {notchSize[0] = context.getResources().getDimensionPixelSize(resourceWidthId);}int resourceHeightId = context.getResources().getIdentifier("notch_height", "dimen", "android");if (resourceHeightId > 0) {notchSize[1] = context.getResources().getDimensionPixelSize(resourceHeightId);}}return notchSize;}//获取vivo、oppo刘海屏、水滴屏的高度:官方没有给出标准的获取刘海高度的API,由于大多情况是:状态栏≥刘海,因此此处获取刘海高度采用状态栏高度public static int getNotchHeight(Context context){int notchHeight = 0;if(isNotch_VIVO(context) || isNotch_OPPO(context)) {//若不想采用状态栏高度作为刘海高度或者可以采用官方给出的刘海固定高度:vivo刘海固定高度:27dp(need dp2px)  oppo刘海固定高度:80pxint resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");if (resourceId > 0) {notchHeight = context.getResources().getDimensionPixelSize(resourceId);}}return notchHeight;}//dp转pxprivate int dp2px(Context context,float dpValue){float scale=context.getResources().getDisplayMetrics().density;return (int)(dpValue*scale+0.5f);}
}

若需要对厂商进行判断可以使用:

//判断手机厂商:华为、小米、oppo、vivo
String brand =android.os.Build.BRAND.toLowerCase();
if("huawei".equals(brand)){//...
}else if("xiaomi".equals(brand)){//...
}else if("vivo".equals(brand)){//...
}else if("oppo".equals(brand)){//...
}

根据四大厂商官网所提供的适配方案,其中需要在AndroidManifest中添加标签(具体说明请浏览官网):

<!-- 适配全面屏 Android O vivo&oppo-->
<meta-data android:name ="android.max_aspect" android:value ="2.2" />
<!-- 适配刘海屏、水滴屏 Android O 小米 -->
<meta-data android:name="notch.config" android:value="portrait|landscape"/>
<!-- 适配刘海屏、水滴屏 Android O 华为 -->
<meta-data android:name="android.notch_support" android:value="true"/>

在对于Android P的适配中Google给出了统一的方案(基于Android API 28):

1、AndroidManifest中添加标签:

<!--适配刘海屏、水滴屏 Android P -->
<meta-data android:name="android.vendor.full_screen" android:value="true"/>

2、把TargetVersion提到28,miniVersion提到23

3、刘海屏判别方法

在Build.VERSION.SDK_INT >= 28中提供了以下接口:

DisplayCutout类接口:主要用于获取凹口位置和安全区域的位置等。

方法接口说明
getBoundingRects()返回Rects的列表,每个Rects都是显示屏上非功能区域的边界矩形。
getSafeInsetLeft()返回安全区域距离屏幕左边的距离,单位是px。
getSafeInsetRight()  返回安全区域距离屏幕右边的距离,单位是px。
getSafeInsetTop()返回安全区域距离屏幕顶部的距离,单位是px。
getSafeInsetBottom()返回安全区域距离屏幕底部的距离,单位是px。
final View decorView = getWindow().getDecorView();
decorView.post(new Runnable() {@Overridepublic void run() {DisplayCutout displayCutout = decorView.getRootWindowInsets().getDisplayCutout();Log.e("TAG", "安全区域距离屏幕左边的距离 SafeInsetLeft:" + displayCutout.getSafeInsetLeft());Log.e("TAG", "安全区域距离屏幕右部的距离 SafeInsetRight:" + displayCutout.getSafeInsetRight());Log.e("TAG", "安全区域距离屏幕顶部的距离 SafeInsetTop:" + displayCutout.getSafeInsetTop());Log.e("TAG", "安全区域距离屏幕底部的距离 SafeInsetBottom:" + displayCutout.getSafeInsetBottom());List<Rect> rects = displayCutout.getBoundingRects();if (rects == null || rects.size() == 0) {Log.e("TAG", "不是刘海屏");} else {Log.e("TAG", "刘海屏数量:" + rects.size());for (Rect rect : rects) {Log.e("TAG", "刘海屏区域:" + rect);}}}});

Android P中新增了一个布局参数属性layoutInDisplayCutoutMode,包含了三种不同的模式,如下所示:

模式模式说明
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT只有当DisplayCutout完全包含在系统栏中时,才允许窗口延伸到DisplayCutout区域。 否则,窗口布局不与DisplayCutout区域重叠。
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER该窗口决不允许与DisplayCutout区域重叠。
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES该窗口始终允许延伸到屏幕短边上的DisplayCutout区域。
if ((Build.VERSION.SDK_INT >= 28)) {// 使用官方api判断WindowManager.LayoutParams lp = getWindow().getAttributes();lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;getWindow().setAttributes(lp);    //不显示状态栏             getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);//初始化时先写适配刘海屏的方法,再判断是否有刘海屏getCutoutLengthAndroidP(context,window);return;
}

 


http://www.ppmy.cn/news/192224.html

相关文章

android兼容小米xiaomi刘海屏解决方案

引用自小米官方文档&#xff0c;这里缩减了一些内容&#xff0c;捡取重要内容。 转载请标明出处&#xff1a; https://blog.csdn.net/DJY1992/article/details/80688376 本文出自:【奥特曼超人的博客】 推荐&#xff1a; android 兼容所有刘海屏的方案大全android 兼容huaw…

Android刘海屏、水滴屏全面屏适配详解,androidui基础教程

适配方式 适配方式有两种&#xff1a; 将targetSdkVersion版本设置到API 24及以上&#xff1b; 这个操作将会为<application> 标签隐式添加一个属性&#xff0c;android:resizeableActivity“true”, 该属性的作用后面将详细说明。 在 标签中增加属性&#xff1a;and…

Android刘海屏、水滴屏全面屏适配详解大厂直通车!

为什么想跳槽&#xff1f; 简单说一下当时的状况&#xff0c;我在这家公司做了两年多&#xff0c;这两年多完成了一个大项目&#xff0c;作为开发的核心主力&#xff0c;开发压力很大&#xff0c;特别是项目上线前的几个月是非常辛苦&#xff0c;几乎每晚都要加班到12点以后&a…

Android适配全面屏/刘海屏

目前国内厂商已经推出的刘海屏Android手机有华为P20 pro&#xff0c; vivo X21&#xff0c;OPPO R15。 1.华为刘海屏的官方适配文档 https://devcenter-test.huawei.com/consumer/cn/devservice/doc/50114 2.oppo刘海屏官方文档&#xff1a; https://open.oppomobile.com/…

浅谈Maven依赖冲突与依赖管理

目录 什么是依赖冲突 为什么会产生冲突 依赖冲突的解决和避免 Maven的仲裁机制

网络安全真的那么好吗?

当你开始在网上搜索关于网络安全的学习资料&#xff0c;常常会陷入自我怀疑&#xff1a;尝试自学后能使用工具进行简单的扫描和挖洞&#xff0c;但总感觉后期学习很难有突破&#xff0c;不知道是哪里出现问题…于是又不得不推倒重来。 了解网络安全&#xff0c;首先要搞清楚下…

django-vue-admin使用

一、源码地址 注意&#xff0c;一定要使用这个地址。&#xff08;使用其他地址下载下来的感觉代码缺失&#xff0c;踩了大坑&#xff09; django-vue-admin: 基于RBAC模型的权限控制的一整套基础开发平台&#xff0c;前后端分离&#xff0c;后端采用 djangodjango-rest-frame…

无线鼠标好用吗

无线鼠标最大的优势就是可以距离电脑更远&#xff0c;实现较远地方操作&#xff0c;适合家用HTPC用户以及追求极致的无线体验用户。比起有线键鼠左一条线&#xff0c;右一条线&#xff0c;可以保证电脑桌面的简洁&#xff0c;省掉了线路连接的杂乱。如果是商旅办公人士经常需要…