Android 从XML动态获取状态栏高度

Android 从XML动态获取状态栏高度,android,android-layout,Android,Android Layout,我需要优化我的Android应用程序,使其在手机上看起来更漂亮,比如基本手机 这款手机的状态栏高度与标准的25dp值不同,因此不能硬编码该值 昨天发布的Android p开发者预览版包括对notch的支持和一些用于查询其位置和边界的api,但对于我的应用程序,我只需要能够从XML获取状态栏高度,而不需要使用固定值 不幸的是,我找不到任何方法从XML中获取该值 有办法吗 谢谢。方法提供状态栏的高度 public int getStatusBarHeight() { int result = 0

我需要优化我的Android应用程序,使其在手机上看起来更漂亮,比如基本手机

这款手机的状态栏高度与标准的25dp值不同,因此不能硬编码该值

昨天发布的Android p开发者预览版包括对notch的支持和一些用于查询其位置和边界的api,但对于我的应用程序,我只需要能够从XML获取状态栏高度,而不需要使用固定值

不幸的是,我找不到任何方法从XML中获取该值

有办法吗


谢谢。

方法提供状态栏的高度

public int getStatusBarHeight() {
  int result = 0;
  int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
 if (resourceId > 0) {
  result = getResources().getDimensionPixelSize(resourceId);
}   
 return result;
}
我已经:

建议使用WindowInsets API,如下所示:

view.setOnApplyWindowInsetsListener { v, insets -> 
    view.height = insets.systemWindowInsetTop // status bar height
    insets
}

访问状态栏高度,因为它是一种私人资源,因此在未来的Android版本中可能会发生变化,这是非常不鼓励的。这不是一个解决方案,但它可以解释如何正确使用状态栏高度,以及如何在引擎盖下运行:

旧解决方案:

这里有一个小技巧:

@*android:dimen/status_bar_height

android studio将向您显示一个错误,但它会像一个符咒一样工作:)

我找到了一个解决方案,可以使用适合任何设备的状态栏大小。这是一种将大小从代码转换为XML布局的方法

解决方案是创建一个使用状态栏大小自动调整大小的视图。它就像来自约束布局的指南

我相信这应该是一个更好的方法,但我没有找到它。如果你考虑改进这个代码,请让我现在:

科特林

class StatusBarSizeView: View {

companion object {

    // status bar saved size
    var heightSize: Int = 0
}

constructor(context: Context):
        super(context) {
    this.init()
}

constructor(context: Context, attrs: AttributeSet?):
        super(context, attrs) {
    this.init()
}

constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int):
        super(context, attrs, defStyleAttr) {
    this.init()
}

private fun init() {

    // do nothing if we already have the size
    if (heightSize != 0) {
        return
    }

    // listen to get the height
    (context as? Activity)?.window?.decorView?.setOnApplyWindowInsetsListener { _, windowInsets ->

        // get the size
        heightSize = windowInsets.systemWindowInsetTop

        // return insets
        windowInsets
    }

}

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(w, h, oldw, oldh)

    // if height is not zero height is ok
    if (h != 0 || heightSize == 0) {
        return
    }

    // apply the size
    postDelayed(Runnable {
        applyHeight(heightSize)
    }, 0)
}

private fun applyHeight(height: Int) {

    // apply the status bar height to the height of the view
    val lp = this.layoutParams
    lp.height = height
    this.layoutParams = lp
}

}
然后您可以在XML中使用它作为指南:

<com.foo.StatusBarSizeView
        android:id="@+id/fooBarSizeView"
        android:layout_width="match_parent"
        android:layout_height="0dp" />

“heightSize”变量是公共变量,如果某些视图需要,可以在代码中使用它


也许这对其他人有帮助。

您的构建可能会在任何稍微现代的版本的构建工具上失败,其中包含“错误:资源android:dimen/status\u bar\u height is private.”。@NPike No。它起作用了。但我同意这绝对不是最好的解决方案…@AndriyAntonov无构建错误,在android N,O上运行良好,但在Pt上运行不好。这在一个谷歌像素上对我有效,而在另一个具有完全相同操作系统的像素上,发布版本崩溃。不幸的是,此解决方案似乎不可靠,不应使用(op来自xml。在ios上有“安全”的布局指南。@skotos的回答对meThis很有效。我们使用Zoom SDK,他们在SDK中声明了这个确切的函数,只是有点不同-
if(resourceId<0)result=25.0f*context.getResources().getDisplayMetrics().density+0.5F;
。如果找不到像某些三星设备那样的resourceId,这将有所帮助。
class StatusBarSpacer @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
View(context, attrs) {
private var statusHeight: Int = 60

init {
    if (context is Activity && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
        context.window.decorView.setOnApplyWindowInsetsListener { _, insets ->
            statusHeight = insets.systemWindowInsetTop
            requestLayout()
            insets
        }
        context.window.decorView.requestApplyInsets()
    } else statusHeight = resources.getDimensionPixelSize(
        resources.getIdentifier("status_bar_height", "dimen", "android")
    )
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) =
    setMeasuredDimension(0, statusHeight)
}