【问题标题】:Height of status bar in Android [duplicate]Android中状态栏的高度[重复]
【发布时间】:2011-03-25 08:23:33
【问题描述】:

Android 中状态栏的高度是多少?总是一样吗?

根据我的测量,它似乎是 25dp,但我不确定它是否在所有平台上都具有相同的高度。

(我想知道这一点以正确实现从没有状态栏的活动到有状态栏的活动的淡入淡出过渡)

【问题讨论】:

  • 如果你做了交叉淡入淡出,那么你不需要知道状态栏的高度。
  • 我确实需要它,因为有些元素在布局中居中,我想让它们相互淡入。

标签: android statusbar


【解决方案1】:

这个问题之前已经回答过... Height of statusbar?

更新::

当前方法:

好的,状态栏的高度取决于屏幕大小,例如在设备中 屏幕尺寸为 240 X 320 时,状态栏高度为 20px,对于屏幕尺寸为 320 X 480 的设备,状态栏高度为 25px,对于屏幕尺寸为 480 x 800 的设备,状态栏高度必须为 38px

所以我推荐使用这个脚本来获取状态栏高度

Rect rectangle = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
int statusBarHeight = rectangle.top;
int contentViewTop = 
    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight= contentViewTop - statusBarHeight;

   Log.i("*** Elenasys :: ", "StatusBar Height= " + statusBarHeight + " , TitleBar Height = " + titleBarHeight); 

(旧方法)在你的Activity的onCreate()方法上获取状态栏的高度,使用这个方法:

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

【讨论】:

  • 不完全是。我还问我是否可以假设状态栏在所有设备中具有相同的高度。
  • 还是使用dip?如果它总是有 25dip,则不需要该代码。
  • 你不能假设它总是 25dp(例如在 kindle fire 上查看高度)。
  • 在 onCreate() 中传递给 view.post() 的 runnable 中不起作用 - 返回 0
  • 如果您处于多窗口模式 + 纵向旋转 + 第二个窗口,window.getDecorView().getWindowVisibleDisplayFrame(rectangle) 不是获取状态栏高度的正确方法。您将获得巨大的价值(包括第一个高度)。
【解决方案2】:

在我用来获取状态栏高度的所有代码示例中,唯一在ActivityonCreate 方法中实际工作的示例如下:

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

显然状态栏的实际高度是作为 Android 资源保存的。上述代码可以添加到ContextWrapper 类中(例如Activity)。

发现于http://mrtn.me/blog/2012/03/17/get-the-height-of-the-status-bar-in-android/

【讨论】:

  • 与其硬编码,不如动态计算。上面的方法对我有用!
  • 你不应该使用 getDimension(...) 吗?
  • 请注意 - 这不适用于所有设备。例如。在 Transformer TF201(以及 TF101、TF300 和其他一些设备)上,高度报告为 25,没有状态栏。
  • 基于上面的 cmets,在我看来,代码告诉您状态栏的高度在特定设备上是什么——而不是在特定活动上是什么(可能不是实际上有一个状态栏)。
  • 在 XML 中可以使用维度资源“@android:dimen/status_bar_height”。 24dp.但是你不能在你的应用项目中直接引用它。所以你必须使用代码。
【解决方案3】:

硬编码大小或使用反射来获取status_bar_height 的值被认为是不好的做法。克里斯·班斯talked about this in at the Droidcon New York。获取状态栏大小的推荐方法是通过OnApplyWindowInsetsListener

myView.setOnApplyWindowInsetsListener { view, insets -> {
  val statusBarSize = insets.systemWindowInsetTop
  return insets
}

这是在 API 20 中添加的,也通过 ViewAppCompat 向后移植。

【讨论】:

  • 这是今天最准确的答案
  • 对我来说这只触发一次,如果我通过底部导航有片段。如果我再次替换片段,则不会调用此侦听器,是否还有兼容的 getter?
  • 然而这个 API 很糟糕,因为幕后的 WTF/Gotchas 数量巨大。你会认为你可以用任何视图来做到这一点,但是不,你需要覆盖某些东西并确保你将插图传递给你的孩子(??)因为一些 ViewGroups 会(材料设计)而所有其他人不会(线性布局?ConstraintLayout?你好?)。而不是系统有一个 Window.getStatusBarSize()…我们必须订阅一个可怕的监听器…回家 Android,你喝醉了。只需对大小进行硬编码,直到 Google 醒来,我们就在 2018 年。我希望 Chris Banes 有一天能看到这一点……
  • 就我而言,它没有被解雇。我把它放在 Activity#onCreated 中。我做错什么了吗?另外我们为什么不使用 mView.getRootWindowInsets()?
  • 你需要调用view.onApplyWindowInsets,否则不会调用视图自己的方法。此外,您的代码在语法上是错误的(大括号错位,闭包中的 return 语句)。
【解决方案4】:

在 MDPI 设备上,状态栏为 25 像素。我们可以以此为基数乘以密度(向上取整)来获得任何设备上的状态栏高度:

int statusBarHeight = Math.ceil(25 * context.getResources().getDisplayMetrics().density);

供参考:ldpi=.75, mdpi=1, hdpi=1.5, xhdpi=2

【讨论】:

  • 这对于具有状态栏的设备是正确的。请注意,由于上述内容已编写,因此并非所有设备都有一个。具体来说,运行 ICS 的设备可能在底部有一个组合状态/导航栏,而在顶部则什么都没有。因此,对于这种情况,对于大多数编程目的,您希望为状态栏分配零高度,但上述公式将为您提供非零大小。
  • 此外,25px 值对于所有 mdpi 设备也不正确。它可能因 API 级别而异。例如,10.1 WXGA 平板电脑模拟器设备在 API 16 和 19 报告 25px,但在 API 24 报告 24px。
【解决方案5】:

我已经将一些解决方案合并在一起:

public static int getStatusBarHeight(final Context context) {
    final Resources resources = context.getResources();
    final int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0)
        return resources.getDimensionPixelSize(resourceId);
    else
        return (int) Math.ceil((VERSION.SDK_INT >= VERSION_CODES.M ? 24 : 25) * resources.getDisplayMetrics().density);
    }

另一种选择:

    final View view = findViewById(android.R.id.content);
    runJustBeforeBeingDrawn(view, new Runnable() {
        @Override
        public void run() {
            int statusBarHeight = getResources().getDisplayMetrics().heightPixels - view.getMeasuredHeight();
        }
    });

编辑:runJustBeforeBeingDrawn 的替代方案:https://stackoverflow.com/a/28136027/878126

【讨论】:

  • getResources().getDisplayMetrics().heightPixels -getActivity().findViewById(android.R.id.content).getMeasuredHeight() 在 android lolipop 中不起作用
  • @ArMo372 更新了答案。只是视图需要先通过测量。如果您已经通过了 runJustBeforeBeingDrawn,则不需要使用它。您只会在过早的情况下使用它。
【解决方案6】:

根据Material Guidance;状态栏高度为 24 dp。

如果您想以像素为单位获取状态栏高度,您可以使用以下方法:

private static int statusBarHeight(android.content.res.Resources res) {
    return (int) (24 * res.getDisplayMetrics().density);
}

可以通过以下方式从活动中调用:

statusBarHeight(getResources());

【讨论】:

  • 直到 Marshmallow 是 25dp。由于 Marshmallow 是 24dp。
  • 这本质上是对值进行硬编码——不允许更改设计
  • 并没有考虑到相同情况下不会显示状态栏
【解决方案7】:

以前的默认高度是 25dp。使用 Android Marshmallow (API 23),高度降低到 24dp。

更新:请注意,自从凹口和打孔相机时代开始以来,使用状态栏的静态高度不再有效。请改用窗口插图!

【讨论】:

  • 甜蜜!我刚刚为 API 级别 23+ 制作了一个 dimens.xml,我将高度硬编码为 24dp。
【解决方案8】:

这也适用于参考link

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

【讨论】:

    【解决方案9】:

    官方身高是24dp, 正如谷歌在Android Design webpage 上正式声明的那样。

    【讨论】:

      【解决方案10】:

      我有同样的问题,必须在 onCreate 中获取状态栏高度。这对我有用。

      private static final int LOW_DPI_STATUS_BAR_HEIGHT = 19;
      
      private static final int MEDIUM_DPI_STATUS_BAR_HEIGHT = 25;
      
      private static final int HIGH_DPI_STATUS_BAR_HEIGHT = 38;
      

      在onCreate里面:

      DisplayMetrics displayMetrics = new DisplayMetrics();
      ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
      
      int statusBarHeight;
      
      switch (displayMetrics.densityDpi) {
          case DisplayMetrics.DENSITY_HIGH:
              statusBarHeight = HIGH_DPI_STATUS_BAR_HEIGHT;
              break;
          case DisplayMetrics.DENSITY_MEDIUM:
              statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
              break;
          case DisplayMetrics.DENSITY_LOW:
              statusBarHeight = LOW_DPI_STATUS_BAR_HEIGHT;
              break;
          default:
              statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
      }
      

      见:

      http://developer.android.com/reference/android/util/DisplayMetrics.html http://developer.android.com/guide/practices/ui_guidelines/icon_design.html

      【讨论】:

      • 我喜欢你使用密度驱动值的想法。如果您要在多个地方使用代码(或使用其他与密度相关的值),我更喜欢将工作卸载到系统,并将值存储在 dimen 资源中,这使得切换变得不必要。您确实需要为每个密度创建一个特定于维度的文件夹和资源文件。最终资源 res = context.getResources(); int statusbarHeight = 0;尝试 { statusbarHeight = res.getDimensionPixelSize(R.dimen.android_statusbar_height); } 捕捉 (NotFoundException e) {}
      • 硬编码这些值很危险,如果它们在以后的平台版本中发生变化怎么办?
      • 我认为与其使用硬编码的像素大小(每个密度一个),不如使用 "25dp" 。
      【解决方案11】:

      是的,当我尝试使用 View 时,它会提供 25px 的结果。 这是整个代码:

      public class SpinActivity extends Activity {
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              LinearLayout lySpin = new LinearLayout(this);
              lySpin.setOrientation(LinearLayout.VERTICAL);       
              lySpin.post(new Runnable()
              {
                  public void run()
                  {
                      Rect rect = new Rect();
                      Window window = getWindow();
                      window.getDecorView().getWindowVisibleDisplayFrame(rect);
                      int statusBarHeight = rect.top;
                      int contentViewTop = 
                          window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
                      int titleBarHeight = contentViewTop - statusBarHeight;
                      System.out.println("TitleBarHeight: " + titleBarHeight 
                          + ", StatusBarHeight: " + statusBarHeight);
                  }
              }
          }
      }
      

      【讨论】:

      • 当我创建一个新的线性布局时,上面的代码对我有用,但是当我从 xml 为 lySpin 执行 findviewbyid 时。然后它返回null。不理解它的行为。
      • 因为布局在 onCreate 中还不知道它的大小,因为它还没有完成绘制。我通常做的是从 onCreate 在 UI 线程上发布一个 Runnable,这让 UI 有时间绘制自己。
      【解决方案12】:

      结合了两种最佳解决方案的 Kotlin 版本

      fun getStatusBarHeight(): Int {
          val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
          return if (resourceId > 0) resources.getDimensionPixelSize(resourceId)
          else Rect().apply { window.decorView.getWindowVisibleDisplayFrame(this) }.top
      }
      
      1. 采用status_bar_height 值(如果存在)
      2. 如果status_bar_height 不存在,则从窗口装饰计算状态栏高度

      【讨论】:

        【解决方案13】:

        240x320 - 20 像素

        320x480 - 25 像素

        480x800+ - 38px

        【讨论】:

        • 这不再准确。使用测量状态栏的方法。
        【解决方案14】:

        试试这个:

            Rect rect = new Rect();
            Window win = this.getWindow();
            win.getDecorView().getWindowVisibleDisplayFrame(rect);
            int statusBarHeight = rect.top;
            int contentViewTop = win.findViewById(Window.ID_ANDROID_CONTENT).getTop();
            int titleBarHeight = contentViewTop - statusBarHeight;
            Log.d("ID-ANDROID-CONTENT", "titleBarHeight = " + titleBarHeight );
        

        它在活动的 onCreate 方法中对我不起作用,但是当我将它放在 onClickListener 中并给我一个 25 的测量值时就起作用了

        【讨论】:

        • 我怀疑他在onCreate()中测试的时候,状态栏还没有创建。相比之下,当他手动单击以激活他的 onClickListener() 代码时,该栏已经有足够的思考时间来显示,他能够检索其大小。
        【解决方案15】:

        android 6.0中状态栏高度为24dp

         <!-- Height of the status bar -->
         <dimen name="status_bar_height">24dp</dimen>
         <!-- Height of the bottom navigation / system bar. -->
         <dimen name="navigation_bar_height">48dp</dimen>
        

        你可以在源码中找到答案:frameworks\base\core\res\res\values\dimens.xml

        【讨论】:

        • 有没有办法在我们的 XML 中获取这个资源? @android:dimen/status_bar_height 不适合我
        【解决方案16】:

        为了解决这个问题,我使用了组合方法。 这是必要的,因为在平板电脑上,系统栏在调用 display.getHeight() 时已经减去了它的像素。 所以我首先检查是否存在系统栏,然后是 Ben Claytons 方法,这在手机上运行良好。

        public int getStatusBarHeight() {
            int statusBarHeight = 0;
        
            if (!hasOnScreenSystemBar()) {
                int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
                if (resourceId > 0) {
                    statusBarHeight = getResources().getDimensionPixelSize(resourceId);
                }
            }
        
            return statusBarHeight;
        }
        
        private boolean hasOnScreenSystemBar() {
            Display display = getWindowManager().getDefaultDisplay();
            int rawDisplayHeight = 0;
            try {
                Method getRawHeight = Display.class.getMethod("getRawHeight");
                rawDisplayHeight = (Integer) getRawHeight.invoke(display);
            } catch (Exception ex) {
            }
        
            int UIRequestedHeight = display.getHeight();
        
            return rawDisplayHeight - UIRequestedHeight > 0;
        }
        

        【讨论】:

          【解决方案17】:

          感谢@Niklas +1,这是正确的做法。

          public class MyActivity extends Activity implements android.support.v4.View.OnApplyWindowInsetsListener {
          
              Rect windowInsets;
          
              @Override
              public void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
          
                  setContentView(R.layout.my_activity);
          
                  View rootview = findViewById(android.R.id.content);
          
                  android.support.v4.View.ViewCompat.setOnApplyWindowInsetsListener(rootview, this);
              }
          
              android.support.v4.View.WindowInsetsCompat android.support.v4.View.OnApplyWindowInsetsListener.OnApplyWindowInsets(View v, android.support.v4.View.WindowInsetsCompat insets)
              {
                  windowInsets = new Rect();
                  windowInsets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
                  //StatusBarHeight = insets.getSystemWindowInsetTop();
          
                  //Refresh/Adjust view accordingly
          
                  return insets;
              }
          }
          

          如果代码不是 100% 正确,请原谅我是从 Xamarin C# 转换而来的,但仅此而已。适用于凹槽等。

          【讨论】:

            【解决方案18】:

            切换全屏解决方案:

            此解决方案可能看起来像是一种解决方法,但它实际上说明了您的应用是否为全屏(也就是隐藏状态栏):

            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point(); display.getSize(size);
            int barheight = size.y - findViewById(R.id.rootView).getHeight();
            

            这样,如果您的应用当前处于全屏状态,barheight 将等于 0。

            就我个人而言,我不得不使用它来纠正 TouchEvent 的绝对坐标来解释状态栏:

            @Override
            public boolean onTouch(View view,MotionEvent event) {
                Display display = getWindowManager().getDefaultDisplay();
                Point size = new Point(); display.getSize(size);
                int YCoord = (int)event.getRawY() - size.y + rootView.getHeight());
            }
            

            无论应用是否全屏,这都会获得绝对 y 坐标。

            享受

            【讨论】:

            • 谢谢,当 android 键盘也显示时,这是唯一对我有用的解决方案。
            【解决方案19】:

            最佳答案对某些人不起作用的原因是,在视图准备好渲染之前,您无法获得视图的尺寸。如果可以,请使用OnGlobalLayoutListener 获取所述尺寸:

            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
            
                final ViewGroup decorView = (ViewGroup) this.getWindow().getDecorView();
                decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        if (Build.VERSION.SDK_INT >= 16) {
                            decorView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                        } else {
                            // Nice one, Google
                            decorView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        }
                        Rect rect = new Rect();
                        decorView.getWindowVisibleDisplayFrame(rect);
                        rect.top; // This is the height of the status bar
                    }
                }
            }
            

            这是最可靠的方法。

            【讨论】:

            • @androiddeveloper OnGlobal != GlobalOn
            • @marijnz0r 真奇怪。这有什么关系?
            • @androiddeveloper 我不知道,但我碰巧也和你几天前的想法一样。见:stackoverflow.com/a/19216041/4587214
            • @marijnz0r 所以两者都做同样的事情。让我想起其他案例,他们为已经存在的东西取了一个新名字,并弃用了之前的名字。示例“fill_parent”与“match_parent”:developer.android.com/reference/android/view/…
            • 这应该是公认的答案!谢谢!
            【解决方案20】:

            在 Android 4.1 及更高版本上,您可以将应用程序的内容设置为显示在状态栏后面,这样内容就不会随着状态栏的隐藏和显示而调整大小。为此,请使用 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN。您可能还需要使用 SYSTEM_UI_FLAG_LAYOUT_STABLE 来帮助您的应用保持稳定的布局。

            当您使用这种方法时,您有责任确保应用 UI 的关键部分(例如,地图应用中的内置控件)最终不会被系统栏覆盖。这可能会使您的应用程序无法使用。在大多数情况下,您可以通过将 android:fitsSystemWindows 属性添加到 XML 布局文件中来处理这个问题,并将其设置为 true。这会调整父 ViewGroup 的填充以为系统窗口留出空间。这对于大多数应用程序来说已经足够了。

            但是,在某些情况下,您可能需要修改默认填充以获得应用所需的布局。要直接操纵您的内容相对于系统栏的布局方式(占据称为窗口“内容插入”的空间),请覆盖 fitSystemWindows(Rect insets)。当窗口的内容插入发生变化时,视图层次结构会调用 fitSystemWindows() 方法,以允许窗口相应地调整其内容。通过覆盖此方法,您可以随心所欲地处理插图(以及应用程序的布局)。

            形式: https://developer.android.com/training/system-ui/status.html#behind

            【讨论】:

              【解决方案21】:

              如果你确切地知道尺寸 VS 高度

              喜欢

              例如,在屏幕尺寸为 320 X 480 的设备中,状态栏高度为 25 像素,对于 480 x 800 的设备,状态栏高度必须为 38 像素

              然后你可以得到你的视图的宽度/屏幕大小你可以使用 if else 语句来得到状态栏的高度

              【讨论】:

              • 根据我的经验,高度似乎是基于密度而不是屏幕尺寸。当然,密度本身通常与屏幕尺寸有关,因此存在间接关系。例如,我的旧 Moto Droid 有一个 480x854(而不是 480x800)的显示屏,状态栏也是 38 像素高。
              • 他们为此发明了 dp(与密度无关的像素)
              【解决方案22】:

              由于现在可以使用多窗口模式,因此您的应用顶部可能没有状态栏。

              以下解决方案会自动为您处理所有案例。

              android:fitsSystemWindows="true"
              

              或以编程方式

              findViewById(R.id.your_root_view).setFitsSystemWindows(true);
              

              您也可以通过

              获得根视图
              findViewById(android.R.id.content).getRootView();
              or
              getWindow().getDecorView().findViewById(android.R.id.content)
              

              有关获取根视图的更多详细信息,请参阅 - https://stackoverflow.com/a/4488149/9640177

              【讨论】:

                【解决方案23】:

                由于我的 Pixel 3XL 中的缺口,这个问题最近与我相关。我真的很喜欢android developer's solution,但我希望能够随意获取状态栏高度,因为它对于我需要播放的全屏动画来说是特别必要的。下面的函数启用了一个可靠的查询:

                private val DEFAULT_INSET = 96
                fun getInsets(view: View?): Int {
                     var inset = DEFAULT_INSET
                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//Safe because only P supports notches
                          inset = view?.rootWindowInsets?.stableInsetTop ?: DEFAULT_INSET
                     }
                     return inset
                }
                
                fun blurView(rootView: View?, a: SpacesActivity?) {
                    val screenBitmap = getBitmapFromView(rootView!!)
                    val heightDifference = getInsets(rootView)
                    val croppedMap = Bitmap.createBitmap(
                                    screenBitmap, 0, heightDifference,
                                    screenBitmap.width,
                                    screenBitmap.height - heightDifference)
                    val blurredScreen = blurBitmap(croppedMap)
                    if (blurredScreen != null) {
                         val myDrawable = BitmapDrawable(a!!.resources, blurredScreen)
                         a.errorHudFrameLayout?.background = myDrawable
                         a.appBarLayout?.visibility = View.INVISIBLE
                   }
                }
                

                然后在activity类中:

                fun blurView() {
                    this.runOnUiThread {
                        Helper.blurView(this)
                    }
                }
                

                您当然希望将活动的弱引用传递给静态 Helper 类方法参数,但为了简洁起见,我在此示例中避免使用。 blurBitmaperrorHudFrameLayout出于同样的原因被省略,因为它们与获取状态栏的高度没有直接关系。

                【讨论】:

                • 如果是 Android P 及更高版本,为什么要检查 Android M ?另外,如果您没有 View 实例,您会怎么做?例如,如果您当前没有 Activity...
                • M 是您可以检查的最早的 stableInsetTop,即使只有 P 支持的缺口,我宁愿获得实际的插图是可能的,而不是在我可以的地方回退到默认值。如果您没有活动,此解决方案将不起作用。
                • 我明白了。谢谢你。你能举一个更“完整”的例子吗?
                • 我将上面的答案更改为在示例中使用该方法。
                猜你喜欢
                • 2012-12-13
                • 2021-04-26
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-11-16
                • 1970-01-01
                • 1970-01-01
                • 2020-04-11
                相关资源
                最近更新 更多