号外!号外!全网第一手Android P刘海屏适配大揭秘,唯一Kotlin算法(1)

2. 搭建环境

在手边没有对应系统的设备的时候,模拟器是一条不错的路,最近 Google 也发布了 Android P 的模拟器,还有一个办法就是找一些支持真机云测的平台,例如华为的云测平台,也是一个解决方案,不过没有本地模拟机这么便捷。

2.1.华为终端开放实验室

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.2.本地模拟器

选择Android P的模拟器,有需要自己更新SDK,下载更新就好。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

刘海的凹槽区域,大部分是为了给摄像头或者其他传感器留出区域。而在没有刘海的设备或者模拟器上,可以通过开发者选项里的 “Simulate a display with a cutout”,开启刘海屏的支持。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Android P模拟器自带四种刘海屏的模式,分别为:“None”、“Narrow display cutout”、“Tall display cutout”和“Wide display cutout”。如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3. 兼容性影响

上面也讲清楚了,刘海屏的切割区域,都存在于状态栏上,所以在有状态栏的页面上,是无需我们特殊处理的,系统会帮我们处理好。

而对于全屏的页面,就需要单独的处理了。我这里,简单做了一个全屏页面,每个横条都是等宽的这样能看到布局上的差异。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个全屏的页面,当没有支持刘海屏又碰到了刘海屏,会导致 UI 下沉,如果这不是一个列表的布局,底部的控件就会被遮挡。

还有一些被刘海遮挡区域的效果,其实主要是依赖 UI 设计师来规避了,不要在可能出现刘海切割的地方,设计可操作的区域,影响用户操作。

4. 官方刘海屏适配

说那么多,最终我们还是需要用技术的方式来适配刘海屏。Android P 的刘海屏,是有标准的Api来进行适配,而对于一些厂商自己的刘海屏设备,例如:OPPO R15,就需要遵循它的开发文档进行单独适配。

Android P 为最新的刘海屏,提供了专门的Api来支持:DisplayCutout

4.1.开启刘海屏

在非刘海屏P版本手机可以开启模拟刘海屏调试的功能

  • 在开发人员选项屏幕中,向下滚动到绘图部分,然后点击“模拟具有凹口的显示屏”设置项
  • 选择刘海尺寸信息

如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.2.适配刘海屏

在刘海屏调试打开之后,浏览应用的所有页面,测试所有遮挡问题,或者是下移导致的问题,对有问题的页面进行布局适配。适配方案如下:

Google 提供的适配方案,可以设置是否在全屏模式下,使用刘海屏的区域。

// 谷歌官方提供的默认适配刘海屏
val attrib = window.attributes
attrib.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS

新的布局属性layoutInDisplayCutoutMode包含三种可选的模式,分别为:

// 窗口声明使用刘海区域
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;
// 默认情况下,全屏窗口不会使用到刘海区域,非全屏窗口可正常使用刘海区域
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;
// 声明不使用刘海区域
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;

4.3.刘海屏的高度

在全屏模式下,我们的应用页面背景充满整个屏幕显示,控件和文字等关键信息布局在状态栏以外的区域,以保证关键信息不会出现遮挡(谷歌要求:凹槽高度和刘海高度要保持一致)。我们需要有办法获取到刘海屏凹槽的高度,才可以做到设计和布局的时候,留出安全距离。

4.3.1. 获取刘海尺寸信息接口

Android P已经预留出了标准的测量刘海屏凹槽的Api:DisplayCutout

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

刘海屏的凹槽,就在屏幕的中间,所以只有**getSafeInsetTop()方法返回的结果,是我们需要的,而其他的getSafeInsetXXX()**方法,直接返回的是0。代码如下所示:

btn_always.postDelayed(Runnable {

val displayCutout = btn_always.rootWindowInsets.displayCutout
if (null == displayCutout) {
Log.e(TAG, “displayCutout is empty”)
return@Runnable
}
Log.i(TAG, “SafeInsetBottom:” + displayCutout.safeInsetBottom);
Log.i(TAG, “SafeInsetLeft:” + displayCutout.safeInsetLeft);
Log.i(TAG, “SafeInsetRight:” + displayCutout.safeInsetRight);
Log.i(TAG, “SafeInsetTop:” + displayCutout.safeInsetTop);

}, 100)

输出结果为:

SafeInsetBottom:0
SafeInsetLeft:0
SafeInsetRight:0
SafeInsetTop:84

4.3.2. 获取系统状态栏高度接口

获取刘海屏的高度之后,我们还要获取系统状态栏的高度,代码如下:

fun getStatusBarHeight(context: Context): Int {

var result = 0

val resourceId = context.resources.getIdentifier(“status_bar_height”, “dimen”, “android”)
if (0 < resourceId) {
result = context.resources.getDimensionPixelOffset(resourceId)
}

return result
}

5. 其他厂商刘海屏适配

像华为、Oppo和Vivo这样的厂商,实现刘海屏的方式,也并不是按照 Android P的标准做的,它完全是自己修改了刘海屏的实现方式。不过他们是会提供完备的适配文档,这就需要我们直接阅读他们提供的开发文档来进行适配。各个厂商的刘海屏适配参考如下:

厂商介绍
华为https://mini.eastday.com/bdmip/180411011257629.html
Oppohttps://open.oppomobile.com/wiki/doc#id=10159
Vivohttps://dev.vivo.com.cn/doc/document/info?id=103

5.1.华为

华为提供了刘海屏Api,可以通过反射的方式调用。

5.1.1. 判断是否刘海屏接口

代码如下:

/**

  • 判断是否是华为刘海屏
  • @param context 上下文对象
  • @return true:是刘海屏;false:非刘海屏
    */
    fun hasNotchInScreen(context: Context): Boolean {
    var ret = false
    try {
    val cl = context.getClassLoader()
    val HwNotchSizeUtil = cl.loadClass(“com.huawei.android.util.HwNotchSizeUtil”)
    val method = HwNotchSizeUtil.getMethod(“hasNotchInScreen”)
    ret = method.invoke(HwNotchSizeUtil) as Boolean

} catch (e: ClassNotFoundException) {
Log.e(TAG, “hasNotchInScreen ClassNotFoundException”)
} catch (e: NoSuchMethodException) {
Log.e(TAG, “hasNotchInScreen NoSuchMethodException”)
} catch (e: Exception) {
Log.e(TAG, “hasNotchInScreen Exception”)
} finally {
return ret
}
}

5.1.2. 获取刘海尺寸信息接口

代码如下:

/**

  • 获取华为刘海的高宽
  • @param context 上下文对象
  • @return [0]值为刘海宽度int;[1]值为刘海高度
    */
    fun getNotchSize(context: Context): IntArray {
    var ret = intArrayOf(0, 0)
    try {
    val cl = context.classLoader
    val HwNotchSizeUtil = cl.loadClass(“com.huawei.android.util.HwNotchSizeUtil”)
    val method = HwNotchSizeUtil.getMethod(“getNotchSize”)
    ret = method.invoke(HwNotchSizeUtil) as IntArray
    } catch (e: ClassNotFoundException) {
    Log.e(TAG, “getNotchSize ClassNotFoundException”)
    } catch (e: NoSuchMethodException) {
    Log.e(TAG, “getNotchSize NoSuchMethodException”)
    } catch (e: Exception) {
    Log.e(TAG, “getNotchSize Exception”)
    } finally {
    return ret
    }
    }

5.1.3. 应用页面设置使用刘海区显示

给window添加华为新增的FLAG_NOTCH_SUPPORT方式,代码如下所示:

/**

  • 设置应用窗口在华为刘海屏手机使用挖孔区
  • @param window 应用页面window对象
    */
    fun setFullScreenWindowLayoutInDisplayCutout(window: Window?) {

if (null == window) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

下面是辛苦给大家整理的学习路线

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

)**

最后

下面是辛苦给大家整理的学习路线

[外链图片转存中…(img-3cQyqHUj-1713533186880)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 19
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我了解了,下面是对于 Kotlin 协程的使用的简要介绍: Kotlin 协程是一种轻量级的并发编程工具,它利用异步非阻塞的方式来提高应用程序的并发性能。在 Kotlin 中,协程提供了一个简单易用的 API 来实现异步操作,这使得编写异步代码变得更加容易。下面是 Kotlin 协程的使用方法: 1.导入协程库 在 Kotlin 中使用协程需要导入协程库。可以在 build.gradle 文件中添加以下代码: ```kotlin dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:version" } ``` 其中 version 是协程库的版本。 2.创建协程 在 Kotlin 中,可以使用 `launch` 函数创建一个协程。以下是一个简单的例子: ```kotlin fun main() { GlobalScope.launch { delay(1000) println("World!") } println("Hello,") Thread.sleep(2000) } ``` 在这个例子中,我们使用 `launch` 函数创建了一个协程,它会在 1 秒后输出 "World!"。在这个协程中,我们使用了 `delay` 函数来模拟一些耗时的操作。在主线程中,我们输出了 "Hello,"。最后,我们使用 `Thread.sleep` 函数等待协程执行完毕。 3.协程作用域 在创建协程时,可以指定协程的作用域。例如,可以使用 `runBlocking` 函数创建一个协程作用域,这个作用域会阻塞当前线程直到所有协程执行完毕。以下是一个例子: ```kotlin fun main() = runBlocking<Unit> { val job = launch { delay(1000) println("World!") } println("Hello,") job.join() } ``` 在这个例子中,我们使用 `runBlocking` 函数创建了一个协程作用域。在这个作用域中,我们创建了一个协程,它会在 1 秒后输出 "World!"。在主线程中,我们输出了 "Hello,"。最后,我们使用 `join` 函数等待协程执行完毕。 4.协程取消 在协程执行过程中,可以通过调用 `cancel` 函数来取消协程。例如,以下是一个例子: ```kotlin fun main() = runBlocking<Unit> { val job = launch { repeat(1000) { i -> println("I'm sleeping $i ...") delay(500) } } delay(1300) println("main: I'm tired of waiting!") job.cancel() job.join() println("main: Now I can quit.") } ``` 在这个例子中,我们创建了一个协程,它会重复执行一些操作。在主线程中,我们等待协程执行了 1.3 秒后,取消了协程。最后,我们等待协程执行完毕并输出一些信息。 这就是 Kotlin 协程的基本使用方法。当然,这只是冰山一角,协程还有很多高级用法,例如协程间通信、异常处理等等。如需了解更多信息,请参考 Kotlin 官方文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值