您的位置:首页 > 移动开发 > Android开发

华为手机适配底部虚拟按键的解决方案

2017-06-02 17:57 706 查看
转载:安卓类似华为手机适配底部虚拟按键的解决方案

场景:华为手机遮挡了屏幕底部。

完美解决方案:

解释一下下面的代码,就是监听某个视图的变化,当可以看见的高度发生变化时,就对这个视图重新布局,保证视图不会被遮挡,也不会浪费屏幕空间。这一点尤其可用在像华为手机等可以隐藏和显示虚拟键盘上导致屏幕变化的手机上。

/**
* Created by win7 on 2016/9/9.
*/
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.
//    private static boolean isKeyBordVisiable;

public static void assistActivity(View content) {
new AndroidBug54971Workaround(content);
}

private View mChildOfContent;
private int usableHeightPrevious;
private ViewGroup.LayoutParams frameLayoutParams;

private AndroidBug54971Workaround(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) {
//如果两次高度不一致

//            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
//            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
//            if (heightDifference > (usableHeightSansKeyboard / 4)) {
//                // keyboard probably just became visible
//                isKeyBordVisiable=true;
//            } else {
//                // keyboard probably just became hidden
//                isKeyBordVisiable=false;
//            }
//将计算的可视高度设置成视图的高度
frameLayoutParams.height = usableHeightNow;
mChildOfContent.requestLayout();//请求重新布局
usableHeightPrevious = usableHeightNow;
}
}

private int computeUsableHeight() {
//计算视图可视高度
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);
}
}


然后在你需要解决这个问题的Activity的onCreate方法的setContentView(R.layout.content_frame);后面添加上

setContentView(R.layout.content_frame);

AndroidBug54971Workaround.assistActivity(findViewById(android.R.id.content));

如果你看的懂代码,你肯定知道assistActivity方法里放入的View是你 要调整高度的视图。

其他不完美方案:或多或少在某些情况上会起不到作用

我一种方法:

Android:fitsSystemWindows=”true”

这句话写在layout的根目录下,看名字就知道是自适应系统窗口。估计能解决很大一部分手机了,可是在同事的nexus 4下并没有什么用。

第二种方法:

我去掉了每个布局的Android:fitsSystemWindows=”true”

在style文件中添加了这句话。

false

注意: 你会发现系统报错,这是因为这句话是在API-19后才有的,所以你可以复制你的style文件,把它放到API-19的文件夹下。这样的用途就是如果手机大于等于API19,就会用API-19的文件夹下的内容。否则用原来的style文件。你在API19文件夹下的style文件的根主题中添加上面这句话就OK啦。

本来我以为是完美解决了我的问题。可是被打脸了。刚进入App时会出现上面的场景2的情况。

我一看MainActivity中的onCreate方法的setContentView(R.layout.xxxx);之前有下面的代码

//控制底部虚拟键盘
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar


// | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar

| View.SYSTEM_UI_FLAG_IMMERSIVE);

估计是这个项目以前的仁兄为了解决这个问题添加的。

经过多次调试,我添加了一句话

//控制底部虚拟键盘
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
//                        | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_IMMERSIVE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);


场景2的情况解决了。这是在虚拟键一直存在的情况下没有问题了,因为nexus不能手动隐藏虚拟键盘,所以我也不清楚是否能在华为等手机上正常运行。TODO。

另外如果想要一直隐藏虚拟键盘,点击屏幕也不会出现的话,将上面的代码换成:

//让虚拟键盘一直不显示
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_IMMERSIVE;
window.setAttributes(params);


就酱样。虽然不懂原理,还是有收获的,记录下来。

基本相同的办法

在我们的项目中加载Fragment的MainActivity,以及其他一般的Activity继承的BaseActivity中的onCreate方法中添加如下代码:

if (AndroidWorkaround.checkDeviceHasNavigationBar(this)) {

AndroidWorkaround.assistActivity(findViewById(android.R.id.content));

}

其中AndroidWorkaround使我们为了解决该问题而封装的类,也可以看作是一个特定的工具类:

/**
* 解决底部屏幕按键适配
* Created by Mercury on 2016/10/25.
*/
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;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息