虚拟导航键显示隐藏监听及自动设定高度
问题描述
某些型号在某些布局下使用虚拟导航栏不能自动调整布局,导致遮挡。特别是华为手机。。。
问题解决步骤
- 获取根布局
- 设置
ViewTree
的全局界面监听
- 当捕获到界面更新时,去判断虚拟导航键是否弹出或隐藏然后做出相应的操作
实现
1. 获取根布局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class MainActivity implements ViewTreeObserver.OnGlobalLayoutListener{
FrameLayout content; private boolean mLayoutComplete = false; ... @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); content = (FrameLayout) findViewById(android.R.id.content); }
@Override public void onGlobalLayout() { ... } ... }
|
2. 设置监听
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); content = (FrameLayout) findViewById(android.R.id.content); content.post(new Runnable() { @Override public void run() { mLayoutComplete = true; LogUtils.d("content 布局完成"); } }); content.getViewTreeObserver().addOnGlobalLayoutListener(this); }
|
3. 捕获监听事件并做出虚拟导航是否隐藏的相应操作
捕获监听
1 2 3 4 5 6
| @Override public void onGlobalLayout() { LogUtils.d("onGlobalLayout"); if (!mLayoutComplete) return; onNavigationBarStatusChanged(); }
|
虚拟导航是否隐藏的相应操作
在这里我判断虚拟导航键是否弹出的依据是 当前屏幕真实高度
是否大于 屏幕高度
。
1 2 3 4 5 6 7 8 9
| protected void onNavigationBarStatusChanged() { if (ScreenUtils.getRealHeight() > ScreenUtils.getHeight()) { getWindow().getDecorView().findViewById(android.R.id.content).setPadding(0, 0, 0,ScreenUtils.getNavigationBarHeight(this)); getWindow().setNavigationBarColor(Color.parseColor("#000000")); } else { getWindow().getDecorView().findViewById(android.R.id.content).setPadding(0, 0, 0, 0); } }
|
4.其他方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class ScreenUtils {
public static int getNavigationBarHeight(Context context){ int result = 0; int resourceId = context.getResources().getIdentifier("navigation_bar_height","dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; }
public static int getHeight() { DisplayMetrics dm = new DisplayMetrics(); WindowManager windowManager = (WindowManager) BaseApplication.getInstance().getSystemService(Context.WINDOW_SERVICE); windowManager.getDefaultDisplay().getMetrics(dm); return dm.heightPixels; }
public static int getRealHeight() { WindowManager windowManager = (WindowManager) BaseApplication.getInstance().getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); DisplayMetrics dm = new DisplayMetrics(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { display.getRealMetrics(dm); } else { display.getMetrics(dm); } int realHeight = dm.heightPixels; return realHeight; } }
|
总结
以下为封装代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
public class ScreenUtils {
public static int getNavigationBarHeight(Context context) { int result = 0; int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; }
public static int getHeight() { DisplayMetrics dm = new DisplayMetrics(); WindowManager windowManager = (WindowManager) BaseApplication.getInstance().getSystemService(Context.WINDOW_SERVICE); windowManager.getDefaultDisplay().getMetrics(dm); return dm.heightPixels; }
public static int getRealHeight() { WindowManager windowManager = (WindowManager) BaseApplication.getInstance().getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); DisplayMetrics dm = new DisplayMetrics(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { display.getRealMetrics(dm); } else { display.getMetrics(dm); } int realHeight = dm.heightPixels; return realHeight; }
public interface NavigationListener { void show();
void hide(); }
public static void setNavigationListener(final View rootView, final NavigationListener navigationListener) { if (rootView == null || navigationListener == null) { return; }
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (ScreenUtils.getRealHeight() > ScreenUtils.getHeight()) { if (navigationListener != null) { navigationListener.show(); } } else { if (navigationListener != null) { navigationListener.hide(); } } } });
} }
|
注: 在使用 setNavigationListener
时,传入的 rootView
为对应的 android.R.id.content
布局(FrameLayout
类型),传入别的可能没有效果。在这里我判断虚拟导航键是否弹出的依据是 当前屏幕真实高度
是否大于 屏幕高度
。
之后在使用时只需要对出现虚拟导航栏出现覆盖问题的 Activity
添加对 rootView
的监听,即可方便的实现虚拟导航栏隐藏与显示的监听。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); content = (FrameLayout) findViewById(android.R.id.content); ScreenUtils.setNavigationListener(content, new ScreenUtils.NavigationListener() { @Override public void show() { }
@Override public void hide() { } }); }
|