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

Android大圆角屏幕适配:InsetsLayout类使用方法及空白屏幕问题求助

Android大圆角屏幕适配:InsetsLayout类使用方法及空白屏幕问题求助

大家好,我现在在做App的Android 16迁移适配,测试大圆角屏幕的虚拟设备时,发现我的视图被屏幕的圆角给“啃”掉了一部分。查了官方文档里的「Apply Rounded Corners」部分,里面提到的InsetsLayout方案正好命中我的需求,于是我照着实现了这个自定义布局类,但官方完全没说具体怎么用这个类。我自己试了一种方式,结果直接出现了空白屏幕,实在搞不定,来求助大家!

我实现的InsetsLayout代码

我按照文档示例实现了这个自定义FrameLayout,还根据@CommonsWare的建议把attrs参数改成了可空类型:

class InsetsLayout(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        val insets = rootWindowInsets
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && insets != null) {
            applyRoundedCornerPadding(insets)
        }
        super.onLayout(changed, left, top, right, bottom)
    }

    @RequiresApi(Build.VERSION_CODES.S)
    private fun applyRoundedCornerPadding(insets: WindowInsets) {
        val topLeft = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)
        val topRight = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT)
        val bottomLeft = insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT)
        val bottomRight = insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT)

        val leftRadius = max(topLeft?.radius ?: 0, bottomLeft?.radius ?: 0)
        val topRadius = max(topLeft?.radius ?: 0, topRight?.radius ?: 0)
        val rightRadius = max(topRight?.radius ?: 0, bottomRight?.radius ?: 0)
        val bottomRadius = max(bottomLeft?.radius ?: 0, bottomRight?.radius ?: 0)

        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val windowBounds = windowManager.currentWindowMetrics.bounds

        val safeArea = Rect(
            windowBounds.left + leftRadius,
            windowBounds.top + topRadius,
            windowBounds.right - rightRadius,
            windowBounds.bottom - bottomRadius
        )

        val location = intArrayOf(0, 0)
        getLocationInWindow(location)

        val leftMargin = location[0] - windowBounds.left
        val topMargin = location[1] - windowBounds.top
        val rightMargin = windowBounds.right - right - location[0]
        val bottomMargin = windowBounds.bottom - bottom - location[1]

        val layoutBounds = Rect(
            location[0] + paddingLeft,
            location[1] + paddingTop,
            location[0] + width - paddingRight,
            location[1] + height - paddingBottom
        )

        if (layoutBounds != safeArea && layoutBounds.contains(safeArea)) {
            setPadding(
                calculatePadding(leftRadius, leftMargin, paddingLeft),
                calculatePadding(topRadius, topMargin, paddingTop),
                calculatePadding(rightRadius, rightMargin, paddingRight),
                calculatePadding(bottomRadius, bottomMargin, paddingBottom)
            )
        }
    }

    private fun calculatePadding(radius1: Int?, radius2: Int?, margin: Int, padding: Int): Int =
        (max(radius1 ?: 0, radius2 ?: 0) - margin - padding).coerceAtLeast(0)
}

我的尝试及遇到的问题

我想着把activity_main的根布局包裹在这个InsetsLayout里,于是在MainActivity的onCreate里写了这段代码:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val parent = InsetsLayout(applicationContext)
    parent.layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.MATCH_PARENT )
    setContentView(parent)
    hideSystemBars()
}

结果运行后直接是空白屏幕,完全看不到原来的布局内容。我的activity_main布局是这样的:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/fondbleufonce"
    android:foregroundTintMode="multiply"
    tools:context=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/navigation_graph"
        tools:layout_editor_absoluteX="18dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

想请教的问题

  • 这个InsetsLayout到底应该怎么正确使用,才能让我的布局自动根据屏幕圆角添加padding,避免被裁切?
  • 我当前的写法为什么会导致空白屏幕?怎么修复?

麻烦各位大佬帮忙看看,谢谢啦!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:08:01