创建 Activity 时如何获取 DisplayCutout 高度?
Posted
技术标签:
【中文标题】创建 Activity 时如何获取 DisplayCutout 高度?【英文标题】:How to get DisplayCutout height when creating an Activity? 【发布时间】:2019-02-10 20:20:06 【问题描述】:我有一个全屏游戏SurfaceView(纵向)和在表面上连续渲染的线程。
SurfaceView 初始化为onCreate
,其大小由屏幕的宽度和高度(以像素为单位)决定。
创建后,设置为 Game Activity 的内容视图(无 XML 定义):
Bitmap frameBuffer = Bitmap.createBitmap(screenWidth, screenHeight, Config.ARGB_8888);
MySurfaceView renderView = new MySurfaceView(this, frameBuffer);
this.setContentView(renderView);
问题是,屏幕高度不包括 Display Cutouts(对于具有它们的设备)并且高于允许的绘图屏幕,因为 renderView 放置在 cutout 区域下方并且不使用它进行渲染。
我试图找到真正的screen height - display cutout height
,以便我可以使帧缓冲区具有那个高度。
你知道是否有办法获得显示剪切区域高度onCreate
,就像我们能够获得导航/状态栏高度一样。下面是一个返回导航栏高度的sn-p:
Resources resources = getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0)
int navigationBarHeight = resources.getDimensionPixelSize(resourceId);
感谢您的帮助!
--- 更新 ---
我会尽量澄清这个问题:
1)onCreate
创建了一个全屏纵向SurfaceView,具有屏幕宽度和高度的尺寸(无XML)
2) API 级别 > 19 (KitKat) 启用沉浸式模式
3) 屏幕宽度和高度由 Display.getSize() 或 Display.getRealSize() 获取,具体取决于 API 级别
4) 在具有顶部显示切口的设备上,视图会自动放置在切口下方,底部内容会被切掉,这就是问题
5) 我想得到 Display Cutout onCreate
的高度,这样我就可以将 SurfaceView 的高度创建为 screenHeight - displayCutoutHeight
。
6) 问题归结为找到 Display Cutout 的高度。
【问题讨论】:
【参考方案1】:WindowInsets.getDisplayCutout()
返回 DisplayCutout
对象(如果存在)。
要获得显示切口的边界矩形,您可以使用
DisplayCutout.getBoundingRects()
它将为您提供屏幕上所有显示切口(非功能区域)的Rect
列表。
为了得到每个显示切口的高度,
Rect.height()
这也可能返回负值,因此请确保采用高度模数。
有关显示切口支持的更多信息,请参阅以下链接:
android:windowLayoutInDisplayCutoutMode
DisplayCutout
layoutInDisplayCutoutMode
WindowInsets
WindowInsets.getDisplayCutout()
【讨论】:
感谢您的回答。我读到我可以使用 WindowInsets 获得它,但我不明白如何在 onCreate 期间获得插图。我已经阅读了您发布的所有链接,所有示例都显示了如何使用视图对象上的侦听器来做到这一点:onApplyWindowInsetsListener。问题是视图放置在插图(切口)下方,并且侦听器始终为切口返回零值,因为它们没有与视图重叠 - 它们在另一个窗口中位于视图上方。您能否提供一个代码 sn-p 您将如何获得 insets 对象?从那里我可以得到 Rect 值。【参考方案2】:似乎没有办法在 onCreate 中获取WindowInsets
对象。您的Activity
必须先附加到窗口。所以你的选择是:
1.
override fun onAttachedToWindow()
val cutout = window.decorView.rootWindowInsets.displayCutout
2.
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
contentView?.setOnApplyWindowInsetsListener _, insets ->
val cutout = insets.displayCutout
return@setOnApplyWindowInsetsListener insets
【讨论】:
【参考方案3】:在 onCreate() 中是这样的:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
drumRoll1Button.addOnLayoutChangeListener(new View.OnLayoutChangeListener()
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
DisplayCutout displayCutout = drumRoll1Button.getRootWindowInsets().getDisplayCutout();
if (displayCutout!=null)
displayCutoutLengthPx = displayCutout.getSafeInsetLeft();
Log.v(LOG_TAG,"displayCutoutLengthPx:"+displayCutoutLengthPx);
);
如果您处于原始问题所要求的纵向模式,请在屏幕上的任何视图(对于drumRoll1Button)和getSafeInsetTop()(对于getSafeInsetLeft())进行交换。此示例适用于景观。
【讨论】:
【参考方案4】:Roman 回答的修改(上图)对我有用:
@Override
public void onAttachedToWindow()
super.onAttachedToWindow();
Log.i("Chicken", "cutout: " + getWindow().getDecorView().getRootWindowInsets().getDisplayCutout());
【讨论】:
请注意,如果您的手机在此方法中旋转过程中稍微旋转了某个角度,您会收到错误提示以上是关于创建 Activity 时如何获取 DisplayCutout 高度?的主要内容,如果未能解决你的问题,请参考以下文章
从 Activity 返回时如何获取最后一个 ListView 状态
在 Activity 重新创建时如何确定 Fragment 恢复?