You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 00:38:13