This will offset your view to account for the NavBar. It's a lengthy response to account for the fragmented behavior of NavBar on different devices.
private static final int ACCOMMODATE_RIGHT = 0b01;
private static final int ACCOMMODATE_BOTTOM = 0b10;
private void prepareNavBar() {
// the progressBar is a good example to use ACCOMODATE_RIGHT | ACCOMODATE_BOTTOM because it touches the bottom and right sides
setViewToAccommodateNavBar((FrameLayout.LayoutParams) footerView.getLayoutParams(), ACCOMMODATE_RIGHT | ACCOMMODATE_BOTTOM);
// the header in the screenshot is a good example to use ACCOMODATE_RIGHT because it only touches the right side
setViewToAccommodateNavBar((FrameLayout.LayoutParams) headerView.getLayoutParams(), ACCOMMODATE_RIGHT);
}
// assumes FrameLayout parent, you can easily extend for other ViewGroups
private void setViewToAccommodateNavBar(FrameLayout.LayoutParams layoutParams, int accommodatingFlag) {
Activity activity = getActivity();
// if navBar does not exist, then we are done because the margins do not need change.
if (!hasNavBar(activity))
return;
// extract flags specified by caller
boolean accommodateRight = (accommodatingFlag & ACCOMMODATE_RIGHT) != 0;
boolean accommodateBottom = (accommodatingFlag & ACCOMMODATE_BOTTOM) != 0;
// these are the only margins that will be affected (NavBar only appears on the bottom or the right)
int rightMargin = layoutParams.rightMargin;
int bottomMargin = layoutParams.bottomMargin;
// if NavBar is on the bottom, then alter bottomMargin. otherwise alter rightMargin
if (isNavBarOnBottom(mContext)) {
if (!accommodateBottom)
return;
boolean isPortrait = mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
String navBarHeightIdName = isPortrait ? "navigation_bar_height" : "navigation_bar_height_landscape";
// it's not public so we resort to reflection.
int resourceId = mContext.getResources().getIdentifier(navBarHeightIdName, "dimen", "android");
if (resourceId > 0) {
bottomMargin += mContext.getResources().getDimensionPixelSize(resourceId);
}
} else {
if (!accommodateRight)
return;
int resourceId = mContext.getResources().getIdentifier("navigation_bar_width", "dimen", "android");
if (resourceId > 0) {
rightMargin += mContext.getResources().getDimensionPixelSize(resourceId);
}
}
// finally, set the margins of your layout.
layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin, rightMargin, bottomMargin);
}
// http://stackoverflow.com/a/30035735/1895452 (my version is slightly modified.)
public static boolean isNavBarOnBottom(Activity activity) {
Point size = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(size);
if ((size.x == size.y)) return true;
if (activity.getResources().getConfiguration().smallestScreenWidthDp >= 600)) return true;
return size.x < size.y;
}
// http://stackoverflow.com/questions/16092431/check-for-navigation-bar
public static boolean hasNavBar() {
boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
return !hasMenuKey && !hasBackKey
}
In summary, first determine your view's navBar accommodations. You can do this by asking yourself, 'does the view touch the right or bottom edge of the screen?' and use the flags accordingly. Then call setViewToAccommodateNavBar. This will add margins to your view's parent taking into account devices with NavBars on either the right or bottom, as well as devices that do not have a NavBar.
prepareNavBar() should be called before the views get drawn eg: onCreate or onCreateView