Android刘海屏适配及view被摄像头遮挡动态改变位置

2023-10-18 02:20

本文主要是介绍Android刘海屏适配及view被摄像头遮挡动态改变位置,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android刘海屏适配及view被摄像头遮挡动态改变位置

目前市面上的刘海屏、水滴屏、挖孔屏越来越多,作为移动开发者来说,这并不是一件好事,越来越多异形屏的出现意味着我们需要投入大量的经历在屏幕适配上,本文总结了当下主流手机的屏幕适配方式(华为、vivo、oppo、小米)以及判断view是否被摄像头遮挡,去动态改变view的位置。

一. Android P及以上

谷歌官方从Android P开始给开发者提供了刘海屏相关的API,可以通过直接调用API来进行刘海屏的适配处理。通过DisplayCutout类可以获得安全区域的范围以及刘海区域(官方的叫法是缺口)的信息,只有API Level在28及以上才可以调用。

1. 判断是否是异形屏

    /*** Android P异形屏判断** @param activity activity* @return 是否是异形屏*/public static boolean isSpecialScreen(Activity activity) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {final View decorView = activity.getWindow().getDecorView();if (decorView != null) {WindowInsets windowInsets = decorView.getRootWindowInsets();if (windowInsets != null) {DisplayCutout cutoutDisp = windowInsets.getDisplayCutout();if(cutoutDisp != null) {displayCutout = cutoutDisp;return true;}}}}return false;}

2. 获取异形屏的刘海高度

    /*** 9.0以上手机,获取异形屏的刘海高度** @return 获取异形屏的刘海高度*/@RequiresApi(28)private static int getNotchHeightFromP() {int notchHeight = 0;if (SwanApp.get() == null || SwanApp.get().getActivity() == null) {return notchHeight;}try {View view = SwanApp.get().getActivity().getWindow().getDecorView();WindowInsets windowInsets = view.getRootWindowInsets();if (windowInsets == null) {return notchHeight;}DisplayCutout displayCutout = windowInsets.getDisplayCutout();if (displayCutout == null) {return notchHeight;}notchHeight = displayCutout.getSafeInsetTop();if (DEBUG) {Log.d(TAG, "刘海屏高度:" + notchHeight);}} catch (Exception e) {if (DEBUG) {Log.w(TAG, e);}}return notchHeight;}

二. Android P以下

对于Android P以下的手机,我们可以通过各个厂商提供的适配方案来进行适配。

1. 华为适配方案

    /*** 判断华为是否有刘海屏** @param context Context* @return hasNotch 是否有刘海屏*/private static boolean hasNotchAtHuawei(@NonNull Context context) {boolean ret = false;try {ClassLoader classLoader = context.getClassLoader();Class HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");ret = (boolean) get.invoke(HwNotchSizeUtil);} catch (Exception e) {if (DEBUG) {e.printStackTrace();}}return ret;}

2. VIVO适配方案

    /*** 判断VIVO是否有刘海屏* <p>* 0x00000020表示是否有凹槽;* 0x00000008表示是否有圆角。** @param context Context* @return hasNotch 是否有刘海屏*/private static boolean hasNotchAtVivo(@NonNull Context context) {boolean ret = false;try {ClassLoader classLoader = context.getClassLoader();Class FtFeature = classLoader.loadClass("android.util.FtFeature");Method method = FtFeature.getMethod("isFeatureSupport", int.class);ret = (boolean) method.invoke(FtFeature, VIVO_NOTCH);} catch (Exception e) {if (DEBUG) {e.printStackTrace();}}return ret;}

3. 小米适配方案

    /*** 判断MIUI是否有刘海屏** @param context Context* @return 是否有刘海屏*/private static boolean hasNotchAtMiui(@NonNull Context context) {boolean ret = false;try {ClassLoader classLoader = context.getClassLoader();Class SystemProperties = classLoader.loadClass("android.os.SystemProperties");Method getInt = SystemProperties.getMethod("getInt", String.class, int.class);ret = (Integer) getInt.invoke(SystemProperties, "ro.miui.notch", 0) == 1;} catch (Exception e) {if (DEBUG) {e.printStackTrace();}}return ret;}

4. OPPO适配方案

    /*** 判断OPPO是否有刘海屏** @param context Context* @return 是否有刘海屏*/private static boolean hasNotchAtOPPO(@NonNull Context context) {return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");}

三. 设置异形屏的显示模式

Android 还允许我们控制是否在刘海区域内显示内容。窗口布局属性 layoutInDisplayCutoutMode 控制您的内容如何呈现在刘海区域中。您可以将 layoutInDisplayCutoutMode 设为以下某个值:

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT - 这是默认行为,在竖屏模式下,内容会呈现到刘海区域中;但在横屏模式下,内容会显示黑边。
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES - 在竖屏模式和横屏模式下,内容都会呈现到刘海区域中。
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER - 内容从不呈现到刘海区域中。

    /*** 设置异形屏的显示模式**@param activity Activity*@param int mode(三种模式)*/public static void setWindowLayoutInDisplayCutoutMode(Activity activity,int mode) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {WindowManager.LayoutParams lp = activity.getWindow().getAttributes();lp.layoutInDisplayCutoutMode = mode;activity.getWindow().setAttributes(lp);}}

四. 判断view是否被摄像头遮挡

刘海屏的摄像头可能在左边、中间、右边,我们可以通过displayCutout.getBoundingRects()获取所有缺口的集合,然后根据缺口的位置判断view是否被遮挡。

    /**** 判断view是否被摄像头遮挡*/public static boolean isViewCovered(Activity activity,View view) {//判断是否是异形屏(里面包含Android P以上及以下异形屏的判断)if (isSpecialshapedScreen(activity) && isAndroidP(activity)) {List<Rect> rects = displayCutout.getBoundingRects();int rectLfet = rects.get(0).left;int rectRight = rects.get(0).right;int rectTop = rects.get(0).top;int rectBottom = rects.get(0).bottom;int[] location = new  int[2] ;view.getLocationOnScreen(location); //获取在整个屏幕内的绝对坐标,含statusBarint width = view.getWidth();int height = view.getHeight();int left = location[0];int right = location[0] + width;int top = location[1];int bottom = location[1] + height;if (((bottom <= rectBottom && bottom > rectTop) || (top < rectBottom && top >= rectTop))&& ((right > rectLfet && right <= rectRight)|| (left >= rectLfet && right <= rectRight)|| (left >= rectLfet && left < rectRight)|| (left < rectLfet && right > rectRight))) {return true;} else if (((left >= rectLfet && left < rectRight) || (right > rectLfet && right <= rectRight))&& ((bottom > rectTop && bottom <=rectBottom)|| (top >= rectTop && bottom <= rectBottom)|| (top >= rectTop && top < rectBottom)|| (top < rectTop && bottom > rectBottom))) {return true;} else if (left <= rectLfet && right >= rectRight && top <= rectTop && bottom >= rectBottom) {return true;}}return false;}
分析:
left 、top、right、bottom分别代表view在屏幕中的左上右下距离。
rectLeft、rectTop、rectRight、rectBottom分别代表刘海屏在屏幕中的左上右下距离。

1.以view的上边或下边为边界,上边或下边在刘海屏的上下之间,view被遮挡的情况有四种。
2.以view的左边或右边为边界,左边或右边在刘海屏的左右之间,view被遮挡的情况有四种。
3.刘海屏被view包围
在这里插入图片描述

五. 动态改变view的位置

当我们判断view被刘海屏遮挡后,就可以改变view的位置,根据需求移动到刘海屏下方或其他。可以通过设置layoutParams,要想获取到view在屏幕中的位置,需要等view绘制完成,所以使用view.post

    /** *伪代码*/view.post(new Runnable() {@Overridepublic void run() {if (isViewCovered(activity,view) ) {List<Rect> rects = cutoutDisp.getBoundingRects();int rectBottom = rects.get(0).bottom;FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();layoutParams.topMargin = mMenu.getTop() + rectBottom;mMenu.setLayoutParams(layoutParams);}}});

Over!!!

这篇关于Android刘海屏适配及view被摄像头遮挡动态改变位置的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/229547

相关文章

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Android使用java实现网络连通性检查详解

《Android使用java实现网络连通性检查详解》这篇文章主要为大家详细介绍了Android使用java实现网络连通性检查的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录NetCheck.Java(可直接拷贝)使用示例(Activity/Fragment 内)权限要求

MyBatis-Plus使用动态表名分表查询的实现

《MyBatis-Plus使用动态表名分表查询的实现》本文主要介绍了MyBatis-Plus使用动态表名分表查询,主要是动态修改表名的几种常见场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录1. 引入依赖2. myBATis-plus配置3. TenantContext 类:租户上下文

2025最新版Android Studio安装及组件配置教程(SDK、JDK、Gradle)

《2025最新版AndroidStudio安装及组件配置教程(SDK、JDK、Gradle)》:本文主要介绍2025最新版AndroidStudio安装及组件配置(SDK、JDK、Gradle... 目录原生 android 简介Android Studio必备组件一、Android Studio安装二、A

Java中的随机数生成案例从范围字符串到动态区间应用

《Java中的随机数生成案例从范围字符串到动态区间应用》本文介绍了在Java中生成随机数的多种方法,并通过两个案例解析如何根据业务需求生成特定范围的随机数,本文通过两个实际案例详细介绍如何在java中... 目录Java中的随机数生成:从范围字符串到动态区间应用引言目录1. Java中的随机数生成基础基本随

基于Nacos实现SpringBoot动态定时任务调度

《基于Nacos实现SpringBoot动态定时任务调度》本文主要介绍了在SpringBoot项目中使用SpringScheduling实现定时任务,并通过Nacos动态配置Cron表达式实现任务的动... 目录背景实现动态变更定时机制配置化 cron 表达式Spring schedule 调度规则追踪定时

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S

Python动态处理文件编码的完整指南

《Python动态处理文件编码的完整指南》在Python文件处理的高级应用中,我们经常会遇到需要动态处理文件编码的场景,本文将深入探讨Python中动态处理文件编码的技术,有需要的小伙伴可以了解下... 目录引言一、理解python的文件编码体系1.1 Python的IO层次结构1.2 编码问题的常见场景二

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

在Android中使用WebView在线查看PDF文件的方法示例

《在Android中使用WebView在线查看PDF文件的方法示例》在Android应用开发中,有时我们需要在客户端展示PDF文件,以便用户可以阅读或交互,:本文主要介绍在Android中使用We... 目录简介:1. WebView组件介绍2. 在androidManifest.XML中添加Interne