API 35与API 31上Edge-to-Edge实现效果不一致的问题求助
Hey there! I totally get the frustration—this is a super common gotcha with how older Android versions handle display cutout insets. Let me break down what's going wrong and how to fix it for you.
问题根源
在API 33(Android 13)之前的版本(比如你的API 31设备),WindowInsetsCompat.Type.displayCutout()的Insets处理逻辑和高版本不一样。当你用|把它和系统栏Insets合并时,会在刘海/挖孔和状态栏重叠的区域重复添加内边距。而API 35(Android 14)已经修复了这个问题,会自动去重重叠的Insets,所以效果正常。这就是为什么你的API 31设备上内容会离刘海太近的原因——相当于在同一个区域加了两次内边距。
修复方案
我们需要避免重复计算重叠区域的内边距,最简单的方式是分别获取系统栏和刘海的Insets,然后对每个方向取两者的最大值,而不是直接相加。这样就能保证不管在哪个版本,都只会添加一次必要的内边距。
下面是修改后的代码:
private void edgeToEdgeIfPossible() { if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT_WATCH) { return; } EdgeToEdge.enable(this); LinearLayout parentLinearLayout = findViewById(R.id.parent_linear_layout); final Rect initialPadding = new Rect( parentLinearLayout.getPaddingLeft(), parentLinearLayout.getPaddingTop(), parentLinearLayout.getPaddingRight(), parentLinearLayout.getPaddingBottom() ); ViewCompat.setOnApplyWindowInsetsListener(parentLinearLayout, (v, insets) -> { // 分别获取系统栏和刘海的Insets Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); Insets cutoutInsets = insets.getInsets(WindowInsetsCompat.Type.displayCutout()); // 对每个方向取最大值,避免重复叠加 int left = initialPadding.left + Math.max(systemBarsInsets.left, cutoutInsets.left); int top = initialPadding.top + Math.max(systemBarsInsets.top, cutoutInsets.top); int right = initialPadding.right + Math.max(systemBarsInsets.right, cutoutInsets.right); int bottom = initialPadding.bottom + Math.max(systemBarsInsets.bottom, cutoutInsets.bottom); v.setPadding(left, top, right, bottom); return insets; }); }
为什么这个方案有效
通过对每个方向的系统栏Insets和刘海Insets取最大值,我们确保了重叠区域不会被重复计算内边距。在API 31上,状态栏的Insets已经覆盖了刘海区域,取最大值就不会额外叠加;在API 35上,这个逻辑也完全兼容,因为系统本身已经处理了重叠,取最大值不会有任何问题。
额外小提示
- 如果你想更精准控制,可以直接判断API版本:只在API 33及以上版本才单独处理刘海Insets,更低版本依赖系统栏Insets即可。
- 确保你用的是最新版的AndroidX Core库,它能让
WindowInsetsCompat在不同版本上的表现更一致。
内容来源于stack exchange

