Android Camera版本适配:API 21至28以下版本中else代码块的实现方法咨询
适配API21-27的刘海屏内边距设置方案
嘿,我来帮你搞定这个API21到27之间的刘海屏适配问题!在Android P(API28)之前,系统并没有提供统一的DisplayCutout API来获取刘海区域,所以我们得针对主流厂商的自定义实现来做兼容处理。下面是具体的解决方案:
核心思路
API21-27阶段,华为、小米、OPPO、vivo等厂商各自推出了刘海屏适配的私有API,我们需要通过反射或者读取系统属性的方式来获取刘海的尺寸,然后根据这个尺寸给View设置对应的内边距。
步骤1:编写辅助函数获取刘海尺寸
首先写一个工具函数,用来兼容不同厂商的刘海尺寸获取:
object NotchCompat { // 获取刘海的高度(顶部)和宽度(左右),返回Pair(刘海高度, 刘海宽度),没有刘海则返回(0,0) fun getNotchSize(context: Context): Pair<Int, Int> { // 华为适配 runCatching { val cls = Class.forName("com.huawei.android.util.HwNotchSizeUtil") val method = cls.getMethod("getNotchSize") val size = method.invoke(null) as IntArray return Pair(size[1], size[0]) // size[0]是宽度,size[1]是高度 } // 小米适配 runCatching { val cls = Class.forName("com.android.internal.util.MiuiNotchSizeUtil") val hasNotchMethod = cls.getMethod("hasNotchInScreen") val hasNotch = hasNotchMethod.invoke(null) as Boolean if (hasNotch) { val getNotchSizeMethod = cls.getMethod("getNotchSize") val size = getNotchSizeMethod.invoke(null) as IntArray return Pair(size[1], size[0]) } } // OPPO适配 runCatching { val packageManager = context.packageManager val hasFeature = packageManager.hasSystemFeature("com.oppo.feature.screen.heteromorphism") if (hasFeature) { val prop = getSystemProperty("ro.oppo.screen.heteromorphism") if (prop.isNotEmpty()) { val size = prop.split(",").map { it.toInt() } return Pair(size[1], size[0]) } } } // vivo适配 runCatching { val cls = Class.forName("com.vivo.util.NotchSizeUtil") val hasNotchMethod = cls.getMethod("hasNotchInScreen") val hasNotch = hasNotchMethod.invoke(null) as Boolean if (hasNotch) { val getNotchSizeMethod = cls.getMethod("getNotchSize") val size = getNotchSizeMethod.invoke(null) as IntArray return Pair(size[1], size[0]) } } // 其他厂商或无刘海设备 return Pair(0, 0) } // 反射读取系统属性,避免直接依赖SystemProperties private fun getSystemProperty(key: String): String { return runCatching { val cls = Class.forName("android.os.SystemProperties") val method = cls.getMethod("get", String::class.java) method.invoke(null, key) as String }.getOrDefault("") } }
步骤2:修改你的else块逻辑
现在回到你的padWithDisplayCutout函数,在else块里调用上面的工具函数,获取刘海尺寸后设置padding:
@RequiresApi(Build.VERSION_CODES.P) fun View.padWithDisplayCutout() { fun doPadding(cutout: DisplayCutout?) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { cutout?.let { setPadding( it.safeInsetLeft, it.safeInsetTop, it.safeInsetRight, it.safeInsetBottom ) } ?: setPadding(0, 0, 0, 0) } else { // API21-27的适配逻辑 val (notchHeight, notchWidth) = NotchCompat.getNotchSize(context) // 大部分低版本刘海为顶部居中设计,所以左右内边距设为0,顶部为刘海高度,底部为0 // 如果需要支持侧边刘海(极少情况),可以根据屏幕宽度计算左右内边距 setPadding(0, notchHeight, 0, 0) } } rootWindowInsets?.displayCutout?.let { doPadding(it) } setOnApplyWindowInsetsListener { _, insets -> doPadding(insets.displayCutout) insets } }
额外注意事项
- Manifest配置:部分厂商需要在AndroidManifest中添加对应的meta-data来开启刘海支持:
<!-- 华为 --> <meta-data android:name="android.notch_support" android:value="true"/> <!-- 小米 --> <meta-data android:name="notch.config" android:value="portrait|landscape"/> <!-- OPPO --> <meta-data android:name="com.oppo.screen.heteromorphism" android:value="true"/> <!-- vivo --> <meta-data android:name="android.vivo.notch" android:value="true"/> - 异常防护:所有反射操作都用
runCatching包裹,避免因为厂商版本更新导致反射失败而崩溃。 - 真机测试:建议在主流厂商的API21-27机型上测试,确保适配效果符合预期。
内容的提问来源于stack exchange,提问作者Julia
相关产品推荐
相关产品推荐

