【问题标题】:How to get DisplayCutout height when creating an Activity?创建 Activity 时如何获取 DisplayCutout 高度?
【发布时间】: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 的高度。

【问题讨论】:

    标签: android android-layout surfaceview android-9.0-pie display-cutouts


    【解决方案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());
           }
        

        【讨论】:

        • 请注意,如果您的手机在此方法中旋转过程中稍微旋转了某个角度,您会收到错误提示
        猜你喜欢
        • 1970-01-01
        • 2022-08-02
        • 2014-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-08
        相关资源
        最近更新 更多