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

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目