如何在模拟器中获取摄像头挖孔的DisplayCutout高度?
解决全屏应用中Pixel模拟器摄像头挖孔遮挡及DisplayCutout为null的问题
一、先解决DisplayCutout为null的问题
你遇到的DisplayCutout为null,核心原因是模拟器未启用挖孔模拟或应用未正确进入全屏模式,按以下步骤排查:
1. 启用模拟器的挖孔模拟
Pixel模拟器默认不会显示挖孔,需手动开启:
- 打开模拟器系统设置,进入System > Developer options(若未显示开发者选项,先到About phone连续点击Build number激活)
- 找到Simulate a display with a cutout选项,选择对应类型(比如Pixel 4系列选"Notch",Pixel 6+选"Double cutout")
2. 确保应用进入全屏模式
只有应用处于全屏状态,系统才会返回包含DisplayCutout的WindowInsets。在onCreate中优先添加全屏设置:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 设置全屏,让布局延伸到系统窗口区域 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { getWindow().setDecorFitsSystemWindows(false); } else { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION ); } // 之后再设置Insets监听 getWindow().getDecorView().setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { DisplayCutout cutout = insets.getDisplayCutout(); if (cutout != null) { Log.d("mytag", "left= " + cutout.getSafeInsetLeft() + ", top= " + cutout.getSafeInsetTop()); } else { Log.d("mytag", "Cutout is null"); } } else { Log.d("mytag", "Old API"); } return insets.consumeSystemWindowInsets(); } }); }
注意:必须先设置全屏,再添加Insets监听,否则DisplayCutout仍会返回null。
二、解决控件被挖孔遮挡的问题
你尝试的LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER不生效,是因为全屏设置不正确或模式设置时机不对,按以下方式修复:
1. 正确设置layoutInDisplayCutoutMode
在全屏设置之后,添加代码配置布局模式:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { WindowManager.LayoutParams params = getWindow().getAttributes(); // 让系统自动避开挖孔区域,布局不会延伸到挖孔处 params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; getWindow().setAttributes(params); }
或在styles.xml的Activity主题中配置(更稳定):
<style name="FullscreenTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar"> <item name="android:windowLayoutInDisplayCutoutMode">never</item> <item name="android:windowFullscreen">true</item> <item name="android:windowNoTitle">true</item> </style>
然后在AndroidManifest.xml中给目标Activity应用该主题:
<activity android:name=".MainActivity" android:theme="@style/FullscreenTheme"> ... </activity>
2. 手动调整布局避开挖孔
若需要布局延伸到挖孔区域,仅让特定控件避开,可通过DisplayCutout获取安全区域边距,手动设置控件padding:
@Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { DisplayCutout cutout = insets.getDisplayCutout(); if (cutout != null) { int safeTop = cutout.getSafeInsetTop(); // 给顶部控件设置top padding,避开挖孔 View topView = findViewById(R.id.top_text); topView.setPadding(topView.getPaddingLeft(), safeTop, topView.getPaddingRight(), topView.getPaddingBottom()); } } return insets.consumeSystemWindowInsets(); }
关键注意事项
- 模拟器必须启用挖孔模拟,否则
DisplayCutout始终为null - 必须先设置
setDecorFitsSystemWindows(false)或对应全屏flags,才能触发系统返回包含DisplayCutout的Insets layoutInDisplayCutoutMode的设置必须在全屏设置之后才会生效
内容的提问来源于stack exchange,提问作者Sasha Minsky
相关产品推荐
相关产品推荐

