Dimension of soft buttons bar - android

Is there a way to determine the dimension (width) of the menu bar of devices without hard menu buttons? (like the archos devices).
I need to know the usable dimension of the screen...

This method is very useful in order to set the layout padding in Android KitKat (4.4). Using this, you can avoid the soft buttons bar overlapping over your layout.
The getRealMetrics method is only available with API 17 and +, but I'm only using the following method I wrote for devices on API 19+
#SuppressLint("NewApi")
private int getSoftbuttonsbarHeight() {
// getRealMetrics is only available with API 17 and +
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return 0;
}
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int usableHeight = metrics.heightPixels;
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
int realHeight = metrics.heightPixels;
return realHeight > usableHeight ? realHeight - usableHeight : 0;
}
Tested upon Nexus 5 & Nexus 7 2013.

A very late answer but for anyone that encounters this problem. A simple way to get the amount of usable space offsetting any soft keys/navigation bar or even the status bar, is to use getWindowVisibleDisplayFrame(Rect) from the Apps DecorView. This will load a Rect object with the dimension of the display that is actually usable.
Since you cannot directly get a reference to the Activiy's DecorView, you need to first get the Activity's window using the accessor method, getWindow(). This will return the window object that holds the Activity and other screen elements. To get the decorView that contains the activity as well as the screen decorations i.e. the status bar, navigation bar/soft button bar, call accessor method getDecorView(). Once your have a reference to the DecorView call getWindowVisibleDisplayFrame(Rect) and you will have a loaded Rect object.

Starting Andorid 3.2, the height of system status bar is not included in DisplayMetrics's height, you have to use undocumented APIs (Display.getRawWidth() and Display.getRawHeight()) to get the physical screen width or height.
Method mGetRawW = Display.class.getMethod("getRawWidth");
Method mGetRawH = Display.class.getMethod("getRawHeight");
int nW = (Integer)mGetRawW.invoke(dp);
int nH = (Integer)mGetRawH.invoke(dp);
UPDATED: For API 13-16, you have to use the above code to get real width/height. For API 17+, you can now use the new public API, Display.getRealSize()

for me, in android note 10, I need to get navigation bar height by dimen:
fun getSoftNavigationBarSize(resources: Resources): Int {
var result = 0
val resourceId: Int = resources.getIdentifier("navigation_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}
return result
}

Related

Does getSize() in Android include the height of the status bar?

Is there a way to tell if getSize() includes the height of the status bar? From testing on a few different phones it seems it does on some but not on others and it is frustrating when trying to make everything in the layout line up properly.
After spending a week on this problem and checked Google's documentation & many other posts here on Stackoverflow (about getting the screen size in pixels via getSize(), getRealSize(), getMetrics(DisplayMetrics metrics), getRealMetrics(DisplayMetrics metrics), etc ... I still have no clue about it.
This picture is giving a better picture of the problem.
On some phones and according to the above picture, the line 'Y/2' should be exactly at size.y / 2 (exact half of the screen between the navigation & the status bars), but is actually not in the middle : The 'Not X' distance on my picture is therefore equal to 'X - getStatusBarSize()'.
I have to add that i am using a ring object with an innerRadiusRatio 2.1 in XML.
But i don't think it's the reason because once i am using the code below, it works on phones where getSize() seems to include the height of the status bar :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Screen dimensions
display = getWindowManager().getDefaultDisplay();
size = new Point();
display.getSize(size);
//Get the screen dimensions
maxWidth = size.x
maxHeight = size.y - getStatusBarSize();
}
private int getStatusBarSize() {
Resources resources = getResources();
int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
return resources.getDimensionPixelSize(resourceId);
}
return 0;
}
While it works simply with maxheight = size.y on others phones (where it does not include the status bar height).
Thanks in advance guys for any help !
I was facing to the same issue more or less and this could be helpful :
// Get the size between the status & the navigation bars
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Real size of the screen (full screen)
Point realSize = new Point();
Display realDisplay = getWindowManager().getDefaultDisplay();
realDisplay.getRealSize(realSize);
//Get the screen dimensions
maxWidth = size.x;
maxHeight = size.y;
if (realSize.y - getNavBarSize() == size.y || realSize.y == size.y) {
Log.d(TAG, "onCreate: getSize() includes the status bar size");
maxHeight = size.y - getStatusBarSize();
}
I've had the same question and this is how I solved it.
Display.getSize() only sometimes includes the status bar height.
For the solution with .getRealSize() you also need the navigation bar height.
With the following solution you don't need the navigation bar height:
View contentView = requireActivity().getWindow().findViewById(Window.ID_ANDROID_CONTENT);
int height = contentView.getHeight() - statusBarHeight - actionBarHeight;
(You might have to get the height in contentView.post() if it returns 0.)

Galaxy S8: screen height returning wrong value

This is how we're getting screen height:
getResources().getDisplayMetrics().heightPixels;
The problem we're having is that with the Galaxy S8's hidden nav bar, the value returned is the height minus the nav bar size (even though the nav bar is hidden by the user). How do we get the full usable height?
example: screen height is 2220 pixels but the value returned is 2076
The answer needs to be able to work on Galaxy S8 with or without the nav bar hidden as well as other devices
thank you so much in advance
Try to use this :
Point displaySize = new Point();
activity.getWindowManager().getDefaultDisplay().getRealSize(displaySize);
Point is a class from android.graphics package.
From docs : https://developer.android.com/reference/android/view/Display.html#getRealSize(android.graphics.Point)
Gets the real size of the display without subtracting any window decor
or applying any compatibility scale factors.
The size is adjusted based on the current rotation of the display.
The real size may be smaller than the physical size of the screen when
the window manager is emulating a smaller display (using adb shell wm
size).
Edit :
I checked this code on LG G4 and it works fine :
//get the full height of device
Point displaySize = new Point();
getWindowManager().getDefaultDisplay().getRealSize(displaySize);
Resources resources = getResources();
int navBarId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
int fullHeight = displaySize.y;
//get nav bar size
int navbarSize = resources.getDimensionPixelSize(navBarId);
int availableSize = fullHeight;
//check is navbar is visible
boolean navBarVisible = (getWindow().getDecorView().getSystemUiVisibility() &
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
if(navBarVisible){
availableSize -= navbarSize;
}
Also you can use this code :
view.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int i) {
Log.d("Nav bar visible : ", String.valueOf((i & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)==0));
}
});
to check when nav bar is hiding.
I had the same problem and could solve this with the decorview:
//Get the correct screen size even if the device has a hideable navigation bar (e.g. the Samsung Galaxy S8)
View decorView = getWindow().getDecorView(); //if you use this in a fragment, use getActivity before getWindow()
Rect r = new Rect();
decorView.getWindowVisibleDisplayFrame(r);
int screenHeight = r.bottom; // =2220 on S8 with hidden NavBar and =2076 with enabled NavBar
int screenWidth = r.right; // =1080 on S8

How to move the default expandable list group indicator from left to right?

Except for creating your own layout, is there any way to move the group indicator from left side to right side?
I am wondering dose Android has such attribute to handle this?
Also, what exactly android:indicatorStart|End|Left|Right does? I looked at the documentation still have no idea about it.
First there are 2 ways of moving group icon indicator depending on devices android version, thus for devices with sdk version 18 and up (android 4.3 and higher) there is a method called setIndicatorBoundsRelative(left,right), as for the lower versions there is another method called setIndicatorBounds(left,right). Both of the above functions change the bounds of the group indicator where the first parameter will set the a position of the indicator to start from and right will set the position of the indicator to end.
The code:
In the activity where expandablelist is declared and initialized, declare the following as class variables(apart from adapter and view of expandableListView)
DisplayMetrics diaplayMetrics;
int width;
In the on create function:
#Override
onCreate(Bundle savedInstanceState) {
//initialze displayMetrics
metrics = new DisplayMetrics();
//get the metrics of window
getWindowManager().getDefaultDisplay().getMetrics(metrics);
save width of window
width = metrics.widthPixels;
//check version of sdk(android version)
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
//For sdk version bellow 18
expandableListView.setIndicatorBounds(width - GetDipsFromPixel(50), width - GetDipsFromPixel(10));
} else {
//For sdk 18 and above
expandableListView.setIndicatorBoundsRelative(width - GetDipsFromPixel(50), width - GetDipsFromPixel(10));
}
expandableListView.setAdapter(listAdapter);
}
private int GetDipsFromPixel(int pixels) {
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (pixels * scale + 0.5f);
}

Height of statusbar?

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
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;
}
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.
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.
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).
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.
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.
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.
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
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) {
}
});
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().
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
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.
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.
Targeting API 30, I've used successfully updated Nicklas answer (ref:https://stackoverflow.com/a/47125610/2163045)
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
}
}
}

Height of status bar in Android [duplicate]

This question already has answers here:
Height of statusbar?
(14 answers)
Closed 2 years ago.
What's the height of the status bar in Android? Is it always the same?
From my measurements it seems that it's 25dp, but I'm not sure if it has the same height on all platforms.
(I want to know this to properly implement a fade transition from an activity that doesn't have status bar to one that does)
this question was answered before...
Height of statusbar?
Update::
Current method:
ok, the height of the status bar depends on the screen size, for example in a device
with 240 X 320 screen size the status bar height is 20px, for a device with 320 X 480 screen size the status bar height is 25px, for a device with 480 x 800 the status bar height must be 38px
so i recommend to use this script to get the status bar height
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);
(old Method) to 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;
}
Out of all the code samples I've used to get the height of the status bar, the only one that actually appears to work in the onCreate method of an Activity is this:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
Apparently the actual height of the status bar is kept as an Android resource. The above code can be added to a ContextWrapper class (e.g. an Activity).
Found at http://mrtn.me/blog/2012/03/17/get-the-height-of-the-status-bar-in-android/
Hardcoding the size or using reflection to get the value of status_bar_height is considered bad practice. Chris Banes talked about this in at the Droidcon New York. The recommended way of getting the status bar size is via the OnApplyWindowInsetsListener:
myView.setOnApplyWindowInsetsListener { view, insets -> {
val statusBarSize = insets.systemWindowInsetTop
return insets
}
This was added in API 20 and is also backported via ViewAppCompat.
On MDPI devices, the status bar is 25px. We can use this as the base and multiply it by the density (rounded up) to get the status bar height on any device:
int statusBarHeight = Math.ceil(25 * context.getResources().getDisplayMetrics().density);
For reference: ldpi=.75, mdpi=1, hdpi=1.5, xhdpi=2
I've merged some solutions together:
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);
}
another alternative:
final View view = findViewById(android.R.id.content);
runJustBeforeBeingDrawn(view, new Runnable() {
#Override
public void run() {
int statusBarHeight = getResources().getDisplayMetrics().heightPixels - view.getMeasuredHeight();
}
});
EDIT: Alternative to runJustBeforeBeingDrawn: https://stackoverflow.com/a/28136027/878126
According to Material Guidance; height of status bar is 24 dp.
If you want get status bar height in pixels you can use below method:
private static int statusBarHeight(android.content.res.Resources res) {
return (int) (24 * res.getDisplayMetrics().density);
}
which can be called from activity with:
statusBarHeight(getResources());
The default height used to be 25dp. With Android Marshmallow (API 23) the height was reduced to 24dp.
Update: Please be aware that since the age of notches and punch-whole-cameras began, using a static height for the status bar no longer works. Please use window insets instead!
this also work with the refrence 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;
}
Official height is 24dp,
as is stated officially by Google on Android Design webpage.
I have the same problem of having to get the status bar height in an onCreate. This works for me.
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;
Inside the 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;
}
See:
http://developer.android.com/reference/android/util/DisplayMetrics.html
http://developer.android.com/guide/practices/ui_guidelines/icon_design.html
Kotlin version that combines two best solutions
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
}
Takes status_bar_height value if present
If status_bar_height is not present, calculates the status bar height from Window decor
Yes when i try it with View it provides the result of 25px.
Here is the whole code :
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);
}
}
}
}
240x320 - 20px
320x480 - 25px
480x800+ - 38px
Try this:
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 );
it didn't work for me in the onCreate method for the activity, but did when I put it in an onClickListener and gave me a measurement of 25
the height of the status bar is 24dp in android 6.0
<!-- 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>
you can find the answer in the source code: frameworks\base\core\res\res\values\dimens.xml
To solve this, I used a combination approach.
This is necessary as on tablets the system bar already subtracts it's pixels when display.getHeight() is called.
So I first check if a system bar is present, and then Ben Claytons approach, which works fine on phones.
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;
}
Thanks to #Niklas +1 this is the correct way to do it.
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;
}
}
Please excuse me if the code isn't 100% correct, converted it from Xamarin C# but this is the just of it. Works with Notches, etc.
Toggled Fullscreen Solution:
This solution may look like a workaround, but it actually accounts for whether your app is fullscreen (aka hiding the status bar) or not:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point(); display.getSize(size);
int barheight = size.y - findViewById(R.id.rootView).getHeight();
This way, if your app is currently fullscreen, barheight will equal 0.
Personally I had to use this to correct absolute TouchEvent coordinates to account for the status bar as so:
#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());
}
And that will get the absolute y-coordinate whether the app be fullscreen or not.
Enjoy
The reason why the top answer does not work for some people is because you cannot get the dimensions of a view until it is ready to render. Use an OnGlobalLayoutListener to get said dimensions when you actually can:
#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
}
}
}
This is the most reliable method.
On Android 4.1 and higher, you can set your application's content to appear behind the status bar, so that the content doesn't resize as the status bar hides and shows. To do this, use SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN. You may also need to use SYSTEM_UI_FLAG_LAYOUT_STABLE to help your app maintain a stable layout.
When you use this approach, it becomes your responsibility to ensure that critical parts of your app's UI (for example, the built-in controls in a Maps application) don't end up getting covered by system bars. This could make your app unusable. In most cases you can handle this by adding the android:fitsSystemWindows attribute to your XML layout file, set to true. This adjusts the padding of the parent ViewGroup to leave space for the system windows. This is sufficient for most applications.
In some cases, however, you may need to modify the default padding to get the desired layout for your app. To directly manipulate how your content lays out relative to the system bars (which occupy a space known as the window's "content insets"), override fitSystemWindows(Rect insets). The fitSystemWindows() method is called by the view hierarchy when the content insets for a window have changed, to allow the window to adjust its content accordingly. By overriding this method you can handle the insets (and hence your app's layout) however you want.
form:
https://developer.android.com/training/system-ui/status.html#behind
If you know exactly the size VS height
like
for example in a device with 320 X 480 screen size the status bar height is 25px, for a device with 480 x 800 the status bar height must be 38px
then you can just get the width of your view / the screen size you can just use an if else statement to get the height of status bar
Since multi-window mode is available now, your app may not have statusbar on top.
Following solution handle all the cases automatically for you.
android:fitsSystemWindows="true"
or programatically
findViewById(R.id.your_root_view).setFitsSystemWindows(true);
you may also get root view by
findViewById(android.R.id.content).getRootView();
or
getWindow().getDecorView().findViewById(android.R.id.content)
For more details on getting root-view refer - https://stackoverflow.com/a/4488149/9640177
This issue recently became relevant for me because of the notch in my Pixel 3XL. I really liked android developer's solution, but I wanted to be able to get the status bar height at will, since it was specifically necessary for a full screen animation that I needed to play. The function below enabled a reliable query:
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
}
}
And then in the activity class:
fun blurView() {
this.runOnUiThread {
Helper.blurView(this)
}
}
You will of course want to make pass a weak reference of the activity to the static Helper class method parameter, but for the sake of brevity I refrained in this example. The blurBitmapand errorHudFrameLayout are omitted for the same reason, since they don't directly pertain to obtaining the height of the status bar.

Categories

Resources