状态栏的高度?


70

有没有一种方法可以获取状态栏和标题栏的高度?检查开发人员论坛会显示相同的问题,但没有解决方案(我可以找到)。

我知道我们可以在初始布局通过后获得它,但是我希望在我的活动的onCreate()中获得它。

谢谢


嗨,我想知道你为什么要达到那个高度?
Jorgesys 2010年

我需要将此活动中托管的
Web视图

material.io给出了答案。>指标:> Android状态栏高度:24dp> Chrome窗口高度:32dp material.io/guidelines/layout / ...
cong

Answers:


102
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop= 
    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;

   Log.i("*** Jorgesys :: ", "StatusBar Height= " + StatusBarHeight + " , TitleBar Height = " + TitleBarHeight); 

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;
} 

10
这是一个重要的假设,即状态栏位于顶部。我希望情况总是如此。
hackbod 2010年

您应该在延迟回调中或在已测量大小的onCreate方法之后调用它。
Roger Alien

正如@hackbod所提到的那样,这假设状态栏位于顶部,如果我们认为Android平板电脑系统栏位于底部,则此操作将失败(但很容易转换为屏幕高度-窗口底部。– 2012
Tom

1
@Tom:我的经验是,当系统栏(导航栏或组合栏)位于底部时,此金额会从DisplayMetrics报告的显示总高度中切出,因此您的应用程序会认为它的尺寸较小可用的绘图空间。这是在针对API 8的应用中,因此,如果您针对更高的目标(例如Honeycomb,其中Nav或组合杠首先开始使用)YMMV。如果需要状态栏高度的原因是要从可用空间中扣除,则可能不需要对底部的NAV或组合栏进行这种扣除。
卡尔

有人也可以指出xml对应对象吗?Kinda像下面这样的操作条尺寸: "?attr/actionBarSize"
Pier Betos

40

对于那些像我一样,想要在您的XML布局中使用它的人:

<...
  android:layout_marginTop="@*android:dimen/status_bar_height"
  ... />

不要被Android Studio(2.2预览版3 –在撰写本文时)不支持此概念所迷惑。运行时可以。我从Google的源代码中获取了它。


13
错误:(30,43)资源不是公共的。(位于“ layout_marginTop”,值为“ @android:dimen / status_bar_height”)。

4
@khan不要忘记星星(*)。这是@ * android:dimen / status_bar_height
Kabir

7
请您解释一下@ * android表示法的含义。谢谢
GPack

3
在api 24之前运行良好,在api 25(android 7.1.1)上崩溃。You must supply a layout_height(width) attribute如果在布局文件上使用它会给您错误。
ntcho

4
在API 21模拟器上,它崩溃并显示为“原因:java.lang.UnsupportedOperationException:无法转换为尺寸:type = 0x1”。
CoolMind

39

尽管这是一个老问题,但我发现答案不适用于onCreate()

我从这里找到了在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;
}

我希望这对遇到此问题的任何人有所帮助。


我在创建动态壁纸时使用了此代码。我找不到任何活动window,因此该功能对我很有用!
Nolesh

10

获取状态栏高度的支持方法是使用WindowInsets从API 21+开始的类:

customView.setOnApplyWindowInsetsListener((view, insets) -> {
    // Handle insets
    return insets.consumeSystemWindowInsets();
});

WindowInsetsCompat用于支持库:

ViewCompat.setOnApplyWindowInsetsListener(customView, (view, insets) -> {
    // Handle insets
    return insets.consumeSystemWindowInsets();
});

您还可以onApplyWindowInsets在视图内覆盖方法:

public class CustomView extends View {
    @Override
    public WindowInsets onApplyWindowInsets(final WindowInsets insets) {
        final int statusBarHeight = insets.getStableInsetTop();
        return insets.consumeStableInsets();
    }
}

有关更多详细信息,我建议检查Chris Banes谈话-成为主窗口装配工此处提供幻灯片)。


@CoolMind能否请您分享在哪个API上无法仔细检查此解决方案?
yarq '17

我在使用API​​ 19、21、23的模拟器上进行了测试。可能是我误会了,对不起。
CoolMind

1
insets.consumeStableInsets()调用具有副作用。最好只调用view.onApplyWindowInsets,该方法将委托返回原始窗口以处理inset。
罗宾·戴维斯

7

我建议下一个代码:

Rect rect = new Rect();
Window window = activity.getWindow();
if (window != null) {
  window.getDecorView().getWindowVisibleDisplayFrame(rect);
  android.view.View v = window.findViewById(Window.ID_ANDROID_CONTENT);

  android.view.Display display = ((android.view.WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

  //return result title bar height
  return display.getHeight() - v.getBottom() + rect.top;   
}

两个例子:

1)设备1品牌:三星,设备:maguro,面板:金枪鱼,cpu_abi:armeabi-v7a,显示屏:ICL53F.M420KREL08,制造商:三星,型号:Galaxy Nexus,版本:4.0.2,版本SD:14 ;

屏幕分辨率:1280 x720。此设备上没有硬件按钮。

结果:

rect: left=0 right=720 top=72 bottom=1208;
v: left=0 right=720 top=72 bottom=1208;
display: height=1208 width=720;
correct result=72;

设备1在屏幕顶部具有标题栏,在屏幕底部具有状态栏和软件按钮。

2)设备2设备:bravo,板卡:bravo,cpu_abi:armeabi-v7a,显示屏:FRG83G,制造商:HTC,型号:HTC Desire,ver.release:2.2.2,ver.sdk:8,

屏幕分辨率:800 x400。此设备具有硬件按钮。

结果:

rect: left=0 right=480 top=38 bottom=800;
v: left=0 right=480 top=0 bottom=800;
display: height=800 width=480;
correct result: phone_bar_height=38;

设备2在屏幕顶部具有标题栏,而根本没有状态栏。

上面提出了两种解决方案:

A) v.getTop() - rect.top 

这对于设备1是不正确的-它给出0而不是72)

B) display.getHeight() - v.getHeight() 

对于设备2不正确-它给出的是0而不是38)

变体:

 display.getHeight() - v.getBottom() + rect.top

在两种情况下都能给出正确的结果。

更新资料

3)再举一个例子(第三个设备):品牌:LGE,设备:v909,cpu_abi:armeabi-v7a,显示:HMJ37,型号:LG-V909,版本发行:3.1,版本SDK:12

rect: left=0 right=1280 top=0 bottom=720
v: left=0 right=1280 top=0 bottom=720
Display: height=768 width=1280
phone_bar_height=48

设备3具有水平方向,在屏幕顶部没有标题栏,而在屏幕底部具有状态栏。

所以在这里:

int size_of_title_bar = rect.top;
int size_of_status_bar = display.getHeight() - v.getBottom();

对设备2和3正确。我不确定设备1。用户向我发送了设备1的屏幕截图。那里有一个带有软件按钮的状态栏。但是表达式“ display.getHeight()-v.getBottom()”给出0。


6

您也可以使用此博客文章的方式,确定在android的dimens.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;
}

您需要将此方法放在ContextWrapper类中。


已经好几年了,不过我还是添加了摘录,因为幸运的是链接仍然有效
LKallipo

4

在您的onCreate方法中将一个可运行对象附加到您的一个视图中,然后将上面的代码放在其中。当它们连接到屏幕时,这将导致应用程序计算状态栏+标题屏幕的高度。

看一下下面的代码:

myView.post(new Runnable() {

        @Override
        public void run() {
            Rect rectgle= new Rect();
            Window window= getWindow();
            window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
            int StatusBarHeight= rectgle.top;
            int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
            int TitleBarHeight= contentViewTop - StatusBarHeight;

        }

    });

如果仍然不能解决问题,请尝试调用视图的postDelayed方法而不是post并添加毫秒值作为第二个参数。


您能解释一下为什么这样安全吗?
tomwhipple 2011年

(返回键使我断断续续...)我看到的文档(developer.android.com/reference/java/lang/Runnable.html)建议这将启动它自己的线程。据我了解,与UI进行交互通常不是线程安全的,即使这样,诸如获取状态栏高度之类的简单操作的性能开销也很高。
tomwhipple 2011年

这不会启动新线程,而是将Runnable添加到UI线程上的消息队列中。查看View类中post方法的文档。在那里解释。 developer.android.com/reference/android/view/...
Kachi

@Felix我知道使用View.post()可以像您所说的那样工作(我自己使用它来在运行时在onCreate()中获取视图的高度)。但是我从来没有完全理解它背后的机制。在view您致电后()上是任意的是否正确?不管view您使用哪种方法Runnable将它们放入相同的UI线程消息队列中?我知道它可以工作,但是有没有解释过posted可运行/消息仅在views被测量并完成layout()之后才运行的地方?
Tony Chan

1

我认为更好的计算方法是获得全屏高度减去我们的主布局

phoneBarsHeight = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight() 
    - mainView.getHeight();

你可以把它放进去 onGlobalLayout()。这也适用于平板电脑,我在Theme.NoTitleBar上尝试过,但必须始终有效。

也许您甚至可以onCreate()通过更改mainView.getHeight()为来增强和使用它mainView.getMeasuredHeight()


不幸的是,getMeasuredHeight()在onCreate中返回0。
Ben Clayton

这可能取决于平台,以此来获取第一测量的第一信息developer.android.com/reference/android/view/...
Mikooos

1
OnCreate还为时过早。您可以在onResume中的视图上调用getMeasuredHeight。那是您的视图应该可见时的回调。
speedynomads 2013年

1

Jorgesys发布的解决方案非常好,但是在onCreate()方法中不起作用。我猜这是因为statusbar和titlebar是在onCreate()之后创建的。

解决方案很简单-您应该将代码放入可运行的内部,并通过使用onCreate()之后执行它 root.post((Runnable action) );

所以整个解决方案:

root = (ViewGroup)findViewById(R.id.root);
root.post(new Runnable() { 
        public void run(){
            Rect rectgle= new Rect();
            Window window= getWindow();
            window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
            int StatusBarHeight= rectgle.top;
            int contentViewTop= 
                 window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
            int TitleBarHeight= contentViewTop - StatusBarHeight;

            Log.i("***  jakkubu :: ", "StatusBar Height= " + StatusBarHeight +
               " , TitleBar Height = " + TitleBarHeight);
        }
});

我在这里找到


1

从API 23开始,有一种更好的解决方案来获取状态栏的高度。API 23添加了一项WindowInsets功能,因此您可以使用此代码获取系统插图的大小,在本例中为顶部。

public int getStatusBarHeight() {
    if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        return binding.mainContent.getRootWindowInsets().getStableInsetTop();
    }
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if(resourceId != 0) {
        return getResources().getDimensionPixelSize(resourceId);
    }
    return 0;
}

请注意,getRootWindowInsets()在将视图附加到窗口之后,它将返回null,因此不能直接在其中使用它,onCreate()但是您可以为窗口附加添加侦听器,然后在此处执行此操作-在这里,我将状态栏插入添加到大小隐藏和显示的工具栏以及状态栏。当它显示时,我希望状态栏位于其顶部,因此我将状态栏的高度添加到工具栏的顶部填充中。

    binding.mainContent.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
        @Override
        public void onViewAttachedToWindow(View view) {
            binding.toolbar.setPadding(binding.toolbar.getPaddingLeft(),
                binding.toolbar.getPaddingTop() + getStatusBarHeight(),
                binding.toolbar.getPaddingRight(), binding.toolbar.getPaddingBottom());
            binding.mainContent.removeOnAttachStateChangeListener(this);
        }

        @Override
        public void onViewDetachedFromWindow(View view) {

        }
    });

1

好。最终答案!!!一种没有副作用,依赖于记录的行为,支持Q,保险开关,根据方向&c具有不同状态栏大小的设备的设备。

protected void onCreate(Bundle savedInstanceState) {
     ...
     setContentView(R.layout.activity_main);
     ....
     // Use The topmost view of the activity, which 
    // is guaranteed to be asked about window insets/
     View rootView = findViewById(R.id.root_view_of_your_activity);
     ViewCompat.setOnApplyWindowInsetsListener(rootView, new OnApplyWindowInsetsListener() {
        @Override
        public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) 
    {
        //THIS is the value you want.
        statusBarHeight = insets.getSystemWindowInsetTop();

        // Let the view handle insets as it likes.
        return ViewCompat.onApplyWindowInsets(v,insets);
    }
});

回调发生在onStart()之后,第一次布局之前,并且此后偶尔发生。


0

这看起来似乎无关紧要,但在大多数情况下,人们寻找状态栏高度的原因是要抵消自己的视图,以使他们不会被置于其下方。

通过fitsSystemWindows在视图上进行设置,您可以“按下”以在状态栏上留出空间,这将根据每个设备上状态栏的大小自动完成。填充将添加到该属性设置为的视图中true

请记住,填充将仅添加到层次结构中的第一个视图中,fitSystemWindows设置为true

例如,这适用于状态栏为半透明的情况。确保您将主题设置为没有的活动fitSystemWindows设置,否则填充将被添加到活动中(因为它是层次结构中的第一个)。

本文是该主题的不错的阅读


请记住,在一致的人之所以要在状态栏的高度是因为“填充将只被添加到层次结构中,这会导致复杂的布局无尽的问题首先查看另外CoordinatorLayouts和行为严重破坏fitsSystemWindows。
罗宾Davies
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.