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

相关文章

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

C#如何动态创建Label,及动态label事件

《C#如何动态创建Label,及动态label事件》:本文主要介绍C#如何动态创建Label,及动态label事件,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#如何动态创建Label,及动态label事件第一点:switch中的生成我们的label事件接着,

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js

mybatis-plus 实现查询表名动态修改的示例代码

《mybatis-plus实现查询表名动态修改的示例代码》通过MyBatis-Plus实现表名的动态替换,根据配置或入参选择不同的表,本文主要介绍了mybatis-plus实现查询表名动态修改的示... 目录实现数据库初始化依赖包配置读取类设置 myBATis-plus 插件测试通过 mybatis-plu

Android WebView无法加载H5页面的常见问题和解决方法

《AndroidWebView无法加载H5页面的常见问题和解决方法》AndroidWebView是一种视图组件,使得Android应用能够显示网页内容,它基于Chromium,具备现代浏览器的许多功... 目录1. WebView 简介2. 常见问题3. 网络权限设置4. 启用 JavaScript5. D