Height of statusbar?
Asked Answered
P

14

83

Is there a way to get the height of the statusbar + titlebar? Checking the dev forum shows the same question but no solution (that I could find).

I know we can get it after the initial layout pass, but I'm looking to get it in onCreate() of my activity.

Thanks

Pentagon answered 28/7, 2010 at 16:59 Comment(3)
hi, i was wondering why do you want to get that height?Mascarenas
I need to set the size of a webview hosted in this activity to whatever the available height is (minus titlebar/statusbar) ThanksPentagon
The material.io give the answer. > Metrics: > Android status bar height: 24dp > Chrome window height: 32dp material.io/guidelines/layout/…Gittel
M
116
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); 

Get the Height of the status bar on the onCreate() method of your Activity, use this method:

public int getStatusBarHeight() { 
      int result = 0;
      int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
      if (resourceId > 0) {
          result = getResources().getDimensionPixelSize(resourceId);
      } 
      return result;
} 
Mascarenas answered 28/7, 2010 at 18:43 Comment(5)
This makes a significant assumption that the status bar is at the top. I would expect that to always be the case.Venesection
you should call it in delayed callback or after onCreate method where sizes will be already measured.Klepht
As @Venesection mentioned this assumes that the status bar is at the top, and if we consider Android tablets system bar at the bottom this fails (but could be easily adapter to screen height - window bottom.Hotheaded
@Tom: My experience is that when the system bar (nav or combined) is at the bottom, this amount gets chopped out of the total height of the display reported by DisplayMetrics, so that your app is made to think that it has a smaller available space for drawing. This is in an app that targets API 8, so if you target something higher (e.g., Honeycomb, where Nav or combined bars first started getting used) YMMV. If the reason that you need the height of the status bar is to deduct it from the available space, then you might not need to do that deduction for the NAV or Combined bar at the bottom.Dwyer
Can someone please indicate the xml counterpart as well? Kinda like the following for actionbar size: "?attr/actionBarSize"Nissy
M
47

For those, like me, who want to use it in your XML layouts:

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

Don't be confused by that Android Studio (2.2 Preview 3 -- at the moment of writing) doesn't support this notion. The runtime does. I took it from the Google's source code.

Metanephros answered 9/6, 2016 at 9:20 Comment(10)
Error:(30, 43) Resource is not public. (at 'layout_marginTop' with value '@android:dimen/status_bar_height').Multifaceted
@khan Don't forget the star(*). It's @*android:dimen/status_bar_heightHerc
please, can you explain what means @*android notation. thanksLaryngotomy
I thought this was working until it failed some tests. For me it broke on devices devices running ~ 5.0.1. The margin on these versions was massive and pushed elements off the screen.Wed
Unlike jtsan, in my case this worked well all the way back to API 15.Levator
Working well until api 24, crashes on api 25 (android 7.1.1). It will give you the error You must supply a layout_height(width) attribute if you use it on layout files.Mantegna
@BedrockDev For me it works on 7.1.1 (Google Pixel). Works fine but looks hacky :PPreliminaries
On API 21 emulator it crashes with "Caused by: java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x1".Saltation
Binary XML file line #41: Can't convert value at index 4 to dimension: tStoss
7.1.2: Binary XML file line #45: Binary XML file line #45: You must supply a layout_height attribute.Stander
G
45

Although this is an old question, I found that the answer didn't work in onCreate():

I found this code from here which does work in the onCreate() method

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

I hope this helps to anyone that runs into this issue.

Gavra answered 19/4, 2013 at 19:58 Comment(1)
I used this code when I was creating live wallpaper. I couldn't find any activities to get window, so this function was useful for me!Spirituality
M
12

The supported way of getting status bar height is to use WindowInsets class starting from API 21+:

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

or WindowInsetsCompat for support libraries:

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

You can also override the onApplyWindowInsets method inside the view:

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

For further details, I'd recommend checking Chris Banes talk - Becoming a master window fitter (slides available here).

Magisterial answered 30/10, 2017 at 15:42 Comment(4)
@Saltation Could you please share on which API's it doesn't work to double check this solution?Magisterial
I tested on emulator with API 19, 21, 23. Probably I am mistaken, sorry.Saltation
the insets.consumeStableInsets() call has side-effects. Better to just call view.onApplyWindowInsets, which delegates back to the original window to deal with insets.Doughnut
I think this would be the preferred approach to handle system window insets when implementing edge-to-edge UI on Android (at the time of writing, at least). There is a great series of articles on Medium that goes into depth on the topic here: medium.com/androiddevelopers/…. I can very much recommend reading them.Bellbella
T
9

You could also take the dimension of the status bar found in the dimens.xml file of android using the way that this blog post describes.

This can get the height of the statusbar without the need to wait for drawing.

Quoting the code from the blog post:

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

You need to put this method in a ContextWrapper class.

Transcalent answered 5/2, 2013 at 15:33 Comment(1)
It's years but I've added the snippet nevertheless, since fortunately the link is still aliveTranscalent
A
6

I would suggest next code:

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

Two examples:

1) Device 1 brand: samsung, device: maguro, board: tuna, cpu_abi: armeabi-v7a, display: ICL53F.M420KREL08, manufacturer: samsung, model: Galaxy Nexus, ver.release: 4.0.2, ver.sdk: 14;

Screen resolution: 1280 x 720.There are no hardware buttons on this device.

Results:

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;

Device 1 has title bar at the top of the screen and status bar with software buttons at the bottom of the screen.

2) Device 2 device: bravo, board: bravo, cpu_abi: armeabi-v7a, display: FRG83G, manufacturer: HTC, model: HTC Desire, ver.release: 2.2.2, ver.sdk: 8,

Screen resolution: 800 x 400. This device has hardware buttons.

Results:

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;

Device 2 has title bar at the top of the screen and hasn't status bar at all.

Two solutions were suggested above:

A) v.getTop() - rect.top 

(it is incorrect for device 1 - it gives 0 instead of 72)

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

(it is incorrect for device 2 - it gives 0 instead of 38)

Variant:

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

gives correct results in both cases.

Update

3) One more example (third device): brand: LGE, device: v909, cpu_abi: armeabi-v7a, display: HMJ37, model: LG-V909, ver.release: 3.1, ver.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

Device 3 has horizontal orientation, hasn't title bar at the top of the screen and has status bar at the bottom of the screen.

So, here:

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

It's correct for devices 2 and 3. I am not sure about device 1. User sent me screenshot of device 1. There is a status bar with software button there. But expression "display.getHeight() - v.getBottom()" gives 0.

Altagraciaaltaic answered 27/1, 2012 at 4:38 Comment(0)
A
5

This may seem unrelated but most of the time, the reason that people look for the status bar height is to offset their own views so they are not placed under it.

By setting fitsSystemWindows on the view you want to "push down" to give space to the status bar, it will be done automatically and according to the size of the status bar on each device. Padding will be added to the view that has this property set to true.

Keep in mind that padding will only be added to the first view in the hierarchy with fitSystemWindows set to true

This applies to cases where the status bar is translucent for example. Make sure that you set a Theme to the activity that doesn't have fitSystemWindows set, otherwise the padding will be added to the activity instead (because it's first in the hierarchy).

This article is a good read on the subject

Ariel answered 29/8, 2019 at 16:6 Comment(1)
Keep in mind that the consistent reason why people want the status bar height is because "padding will only be added to the FIRST view in the hierarchy, which causes endless problems in complex layouts. In addition CoordinatorLayouts and behaviours play havoc with fitsSystemWindows.Doughnut
A
4

Attach a runnable to one of your views in your onCreate method, and place the above code in there. This will cause the application to calculate the status bar + titlescreen height when they are attached to the screen.

Take a look at the code below:

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;

        }

    });

If this still doesn't do the trick, try invoking the view's postDelayed method instead of post and adding a millisecond value as the second argument.

Adam answered 25/6, 2011 at 18:19 Comment(4)
Will you explain why this is safe?Tristichous
(return key cut me off...) The docs I see (developer.android.com/reference/java/lang/Runnable.html) suggest that this will start it's own thread. It is my understanding that interacting with the UI is not thread safe in general, and even if it were, the performance overhead for something simple like getting the status bar height is very high.Tristichous
this won't start a new thread, rather it adds the Runnable to the message queue on the UI thread. Take a look at the documentation for the post method in the View class. It is explained in there. developer.android.com/reference/android/view/…Adam
@Felix I know that using View.post() works as you said (I use it myself to get the height of a view at runtime in onCreate()). But I never fully understood the mechanics behind it. The view that you call post() on is arbitrary correct? No matter which view you use the Runnable gets placed into the same UI-thread message queue? I know that it works but is it ever explained anywhere that the posted runnable/message only gets run after the views have been measured and layout() completed?Lysimachus
S
2

As of API 23 there is a better solution to getting the status bar height. API 23 adds a WindowInsets feature, so you can use this code to get the size of the system insets, in this case at the top.

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

Note that getRootWindowInsets() will return null until after the View has been attached to a Window so it can't be used directly in onCreate() but you can add a listener for the window attach and do it there - here I am adding the status bar inset to the size of my toolbar, which I hide and show, along with the status bar. When it's shown, I want the status bar over the top of it so I add the status bar height to the toolbar's top padding.

    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) {

        }
    });
Serif answered 17/1, 2017 at 7:15 Comment(0)
F
2

Current actual way:

Kotlin:

ViewCompat.setOnApplyWindowInsetsListener(toolbar) { view, windowInsets ->
     val insets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars())
     view.updateLayoutParams<MarginLayoutParams> {
         topMargin = insets.top
     }
     WindowInsetsCompat.CONSUMED
}

Java:

ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, windowInsets) -> {
    Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
    ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
    mlp.topMargin = insets.top;
    v.setLayoutParams(mlp);
    return WindowInsetsCompat.CONSUMED;
}

Google recommends using it like this if you want to support edge-to-edge in your app.

Fetishist answered 8/8, 2022 at 14:50 Comment(0)
H
1

I think better way to calculate that is to get height of fullscreen minus our main layout

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

And you can put it in onGlobalLayout(). This works on tablets too, I tried it on Theme.NoTitleBar, but it must always works.

Maybe you can even enhance it and use it onCreate() by changing mainView.getHeight() to mainView.getMeasuredHeight().

Heterodox answered 7/9, 2011 at 7:42 Comment(3)
getMeasuredHeight() returns 0 in the onCreate unfortunately.Brunhilde
It might depends on platform, use this to get first information about first measurement developer.android.com/reference/android/view/…Heterodox
OnCreate is too early. You can call getMeasuredHeight on a view in onResume. That is the callback by when your views should be visible.Spectacled
Z
1

The solution posted by Jorgesys is very good, but it doesn't work inside onCreate() method. I guess it's because statusbar and titlebar are created after onCreate().

The solution is easy - you should put code inside runnable and execute it after onCreate() by using root.post((Runnable action) );

So the whole solution:

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

I find it here

Zora answered 12/9, 2013 at 19:59 Comment(0)
D
1

Ok. Final answer!!! One that does not have side-effects, relies on documented behavior, supports Q, cutouts, devices with different status-bar size depending on orientation, &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);
    }
});

The callback occurs after onStart(), before first layout, and occasionally thereafter.

Doughnut answered 9/2, 2020 at 17:0 Comment(0)
P
0

Targeting API 30, I've used successfully updated Nicklas answer (ref:https://mcmap.net/q/86967/-height-of-status-bar-in-android-duplicate)

In my example I'm adjusting dynamically custom toolbar height in fullscreen WindowCompat.setDecorFitsSystemWindows(window, false) Activity

Tested on GooglePixel 5

class MyActivity : ViewBindingActivity<LayoutBinding>() {
...

    override fun created(binding: LayoutBinding, savedInstanceState: Bundle?) {

        binding.root.setOnApplyWindowInsetsListener { _, insets ->
            val statusBarHeight = insets.getInsets(WindowInsets.Type.statusBars()).top // <- HERE YOU ARE
            val toolbarHeight = getDimenPx(R.dimen.toolbar_height)
            binding.toolbar.layoutParams.height = statusBarHeight + toolbarHeight
            insets
        }
    }
}
Pounce answered 1/2, 2021 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.