先上最终的代码:
public class AndroidWorkaround { public static void assistActivity(View content) { new AndroidWorkaround(content); } private View mChildOfContent; private int usableHeightPrevious; private ViewGroup.LayoutParams frameLayoutParams; private AndroidWorkaround(View content) { mChildOfContent = content; mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { public void onGlobalLayout() { possiblyResizeChildOfContent(); } }); frameLayoutParams = mChildOfContent.getLayoutParams(); } private void possiblyResizeChildOfContent() { int usableHeightNow = computeUsableHeight(); if (usableHeightNow != usableHeightPrevious) { frameLayoutParams.height = usableHeightNow; mChildOfContent.requestLayout(); usableHeightPrevious = usableHeightNow; } } private int computeUsableHeight() { Rect r = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(r); return (r.bottom); } public static boolean checkDeviceHasNavigationBar(Context context) { boolean hasNavigationBar = false; Resources rs = context.getResources(); int id = rs.getIdentifier("config_showNavigationBar", "bool", "android"); if (id > 0) { hasNavigationBar = rs.getBoolean(id); } try { Class systemPropertiesClass = Class.forName("android.os.SystemProperties"); Method m = systemPropertiesClass.getMethod("get", String.class); String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys"); if ("1".equals(navBarOverride)) { hasNavigationBar = false; } else if ("0".equals(navBarOverride)) { hasNavigationBar = true; } } catch (Exception e) { } return hasNavigationBar; } }
注意点:这里构造方法的参数是当前你写的布局view
-----------------------------------------------------------------------------------------------
PS:
1.单单解决输入法挡住软键盘
public class AndroidBug5497Workaround { // For more information, see https://code.google.com/p/android/issues/detail?id=5497 // To use this class, simply invoke assistActivity() on an Activity that already has its content view set. public static void assistActivity(Activity activity) { new AndroidBug5497Workaround(activity); } private Activity activity; private View mChildOfContent; private int usableHeightPrevious; private FrameLayout.LayoutParams frameLayoutParams; private AndroidBug5497Workaround(Activity activity) { this.activity = activity; FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); mChildOfContent = content.getChildAt(0); mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { public void onGlobalLayout() { possiblyResizeChildOfContent(); } }); frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams(); } private void possiblyResizeChildOfContent() { int usableHeightNow = computeUsableHeight(); if (usableHeightNow != usableHeightPrevious) { int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight(); //这个判断是为了解决19之前的版本不支持沉浸式状态栏导致布局显示不完全的问题 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { Rect frame = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); int statusBarHeight = frame.top; usableHeightSansKeyboard -= statusBarHeight; } int heightDifference = usableHeightSansKeyboard - usableHeightNow; if (heightDifference > (usableHeightSansKeyboard / 4)) { // keyboard probably just became visible frameLayoutParams.height = usableHeightSansKeyboard - heightDifference; } else { // keyboard probably just became hidden frameLayoutParams.height = usableHeightSansKeyboard; } mChildOfContent.requestLayout(); usableHeightPrevious = usableHeightNow; } } private int computeUsableHeight() { Rect frame = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); int statusBarHeight = frame.top; Rect r = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(r); //这个判断是为了解决19之后的版本在弹出软键盘时,键盘和推上去的布局(adjustResize)之间有黑色区域的问题 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { return (r.bottom - r.top) + statusBarHeight; } return (r.bottom - r.top); } }
2.单单解决华为手机虚拟按键挡住底部界面
public class AndroidBug54971Workaround { // For more information, see https://code.google.com/p/android/issues/detail?id=5497 // To use this class, simply invoke assistActivity() on an Activity that already has its content view set. /** * 关联要监听的视图 * * @param viewObserving */ public static void assistActivity(View viewObserving) { new AndroidBug54971Workaround(viewObserving); } private View mViewObserved;//被监听的视图 private int usableHeightPrevious;//视图变化前的可用高度 private ViewGroup.LayoutParams frameLayoutParams; private AndroidBug54971Workaround(View viewObserving) { mViewObserved = viewObserving; //给View添加全局的布局监听器 mViewObserved.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { public void onGlobalLayout() { resetLayoutByUsableHeight(computeUsableHeight()); } }); frameLayoutParams = mViewObserved.getLayoutParams(); } private void resetLayoutByUsableHeight(int usableHeightNow) { //比较布局变化前后的View的可用高度 if (usableHeightNow != usableHeightPrevious) { //如果两次高度不一致 //将当前的View的可用高度设置成View的实际高度 frameLayoutParams.height = usableHeightNow; mViewObserved.requestLayout();//请求重新布局 usableHeightPrevious = usableHeightNow; } } /** * 计算视图可视高度 * * @return */ private int computeUsableHeight() { Rect r = new Rect(); mViewObserved.getWindowVisibleDisplayFrame(r); return (r.bottom - r.top); } }
注意点:setContentView(R.layout.content_frame);
AndroidBug54971Workaround.assistActivity(findViewById(android.R.id.content));