How do I get the height and width of the Android Navigation Bar programmatically?
Categories:
Programmatically Obtaining Android Navigation Bar Dimensions

Learn how to accurately retrieve the height and width of the Android system navigation bar using various programmatic approaches, ensuring your app's UI adapts correctly.
Developing Android applications often requires precise control over UI layout to ensure a seamless user experience across a multitude of devices. A common challenge arises when dealing with system UI elements like the navigation bar. Depending on the device, Android version, and user settings, the navigation bar can be present at the bottom or side of the screen, or even hidden. Knowing its dimensions programmatically is crucial for tasks such as adjusting view paddings, calculating available screen space, or preventing UI elements from being obscured.
Understanding the Android Navigation Bar
The Android navigation bar typically houses the 'Back', 'Home', and 'Recents' buttons. Its position and visibility can vary:
- Bottom: Most common configuration for phones.
- Side (Right/Left): Common on tablets or foldable devices in certain orientations.
- Hidden: When an app enters immersive mode or the user has gesture navigation enabled.
Accurately determining its size is not always straightforward, as it's a system-level UI component. We'll explore methods that account for these variations.
flowchart TD A[Start] --> B{Is Navigation Bar Visible?} B -- Yes --> C{Get Display Metrics} C --> D{Calculate Real Screen Size} D --> E{Calculate App Window Size} E --> F{Determine Nav Bar Height/Width} B -- No --> G[Nav Bar Dimensions = 0] F --> H[End] G --> H
Flowchart for determining navigation bar dimensions
Method 1: Using WindowInsets
(Recommended for API 21+)
For modern Android development (API level 21 and above), WindowInsets
provide a robust and accurate way to determine the dimensions of system UI elements, including the navigation bar. This approach is preferred because it correctly accounts for various system UI states and configurations, such as gesture navigation or immersive mode.
WindowInsets
are delivered to views when the system UI changes. You can listen for these changes and query the insets for the navigation bar.
import android.graphics.Rect
import android.os.Build
import android.view.View
import android.view.WindowInsets
import androidx.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.R)
fun getNavigationBarHeightApi30(view: View, callback: (Int) -> Unit) {
view.setOnApplyWindowInsetsListener { v, insets ->
val systemInsets = insets.getInsets(WindowInsets.Type.systemBars())
val navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars())
// The navigation bar height is typically the bottom inset of navigationBars()
// or the difference between systemBars() and statusBars() if nav bar is at bottom
val navBarHeight = navBarInsets.bottom
callback(navBarHeight)
insets
}
// Request insets dispatch if not already dispatched
view.requestApplyInsets()
}
@RequiresApi(Build.VERSION_CODES.Q)
fun getNavigationBarHeightApi29(view: View, callback: (Int) -> Unit) {
view.setOnApplyWindowInsetsListener { v, insets ->
val navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars())
callback(navBarInsets.bottom)
insets
}
view.requestApplyInsets()
}
// For older APIs (21-28), you might need to combine with other methods or use deprecated ones.
// A more general approach for API 21+ can be found using WindowInsetsCompat from AndroidX.
// Example usage in an Activity or Fragment:
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// super.onViewCreated(view, savedInstanceState)
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// getNavigationBarHeightApi30(view) { height ->
// Log.d("NavBar", "Navigation Bar Height (API 30+): $height px")
// }
// } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// getNavigationBarHeightApi29(view) { height ->
// Log.d("NavBar", "Navigation Bar Height (API 29): $height px")
// }
// } else {
// // Fallback for older APIs or use WindowInsetsCompat
// val navBarHeight = getNavigationBarHeightLegacy(requireActivity())
// Log.d("NavBar", "Navigation Bar Height (Legacy): $navBarHeight px")
// }
// }
WindowInsetsCompat
from AndroidX. This provides a unified API for handling window insets, abstracting away API level differences.Method 2: Calculating Difference Between Real and App Display Size (Legacy)
For older Android versions (pre-API 29) or as a fallback, you can calculate the navigation bar's dimensions by comparing the total screen size (including system decorations) with the application's usable display size. This method is less reliable than WindowInsets
but can work in many scenarios.
This approach involves:
- Getting the 'real' screen dimensions using
DisplayMetrics
andgetRealSize()
. - Getting the application's usable screen dimensions using
DisplayMetrics
andgetSize()
orgetRectSize()
. - The difference in height (or width, for side navigation bars) often corresponds to the navigation bar's size.
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
public class NavigationBarUtils {
public static int getNavigationBarHeight(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (windowManager == null) {
return 0;
}
Display display = windowManager.getDefaultDisplay();
DisplayMetrics realMetrics = new DisplayMetrics();
display.getRealMetrics(realMetrics);
int realHeight = realMetrics.heightPixels;
int realWidth = realMetrics.widthPixels;
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getMetrics(displayMetrics);
int displayHeight = displayMetrics.heightPixels;
int displayWidth = displayMetrics.widthPixels;
// Check if navigation bar is at the bottom
if (realHeight > displayHeight) {
return realHeight - displayHeight;
}
// Check if navigation bar is on the side (e.g., landscape tablets)
else if (realWidth > displayWidth) {
return realWidth - displayWidth; // This would be the width of the side nav bar
}
return 0;
}
// Another legacy approach using resources, less reliable for dynamic changes
public static int getNavigationBarHeightUsingResources(Context context) {
int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
return context.getResources().getDimensionPixelSize(resourceId);
}
return 0;
}
// Example usage in an Activity:
// @Override
// protected void onCreate(Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
//
// int navBarHeight = NavigationBarUtils.getNavigationBarHeight(this);
// Log.d("NavBar", "Navigation Bar Height (Legacy Calc): " + navBarHeight + " px");
//
// int navBarHeightRes = NavigationBarUtils.getNavigationBarHeightUsingResources(this);
// Log.d("NavBar", "Navigation Bar Height (Legacy Res): " + navBarHeightRes + " px");
// }
}
getNavigationBarHeightUsingResources()
, are less reliable. They might not reflect the actual navigation bar size if it's dynamically hidden, if gesture navigation is enabled, or if the device manufacturer has customized the resource identifiers. Always prioritize WindowInsets
for modern Android versions.Handling Gesture Navigation
With the introduction of gesture navigation, the traditional navigation bar may no longer be present as a distinct, fixed-size UI element. Instead, the system might draw a small 'gesture bar' at the bottom. WindowInsets
are still the best way to handle this, as WindowInsets.Type.navigationBars()
will return the space reserved for these gestures, allowing your app to avoid overlapping them.
When gesture navigation is active, the navigation_bar_height
resource might return 0 or a very small value, and the difference calculation method might also yield 0. This is the expected behavior, as the system is giving your app more screen real estate.
1. Choose the Right API Level
For API 29 (Android 10) and above, use WindowInsets.Type.navigationBars()
with setOnApplyWindowInsetsListener
. This is the most accurate and future-proof method.
2. Implement WindowInsets
Listener
Attach an OnApplyWindowInsetsListener
to your root view. This listener will be invoked whenever the system UI insets change, providing up-to-date information.
3. Extract Navigation Bar Insets
Inside the listener, use insets.getInsets(WindowInsets.Type.navigationBars())
to get the Insets
object specifically for the navigation bar. Its bottom
, left
, or right
fields will give you the dimensions.
4. Consider Fallbacks (if necessary)
For older API levels (pre-29), you might need to use the getNavigationBarHeight
calculation method or getNavigationBarHeightUsingResources
as a fallback, though these are less reliable.
5. Apply Dimensions to UI
Once you have the dimensions, apply them as padding or margins to your views to prevent content from being obscured by the navigation bar.