这个问题来来回回困扰了我很久,一直没能妥善解决。

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

场景2:进入应用时,虚拟键自动缩回,留下空白区域。

需求:

  • 需要安卓能自适应底部虚拟按键,用户隐藏虚拟按键时应用要占满整个屏幕,当用户启用虚拟键时,应用能往上收缩,等于是被底部虚拟按键顶上来。

  • 需求很简单,实现起来却困难重重。

完美解决方案:

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

  • 首先添加工具类AndroidBug54971Workaround
package com.xxxx.xxxx;

import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver; /**
* Created by win7 on 2016/12/14.
*/ 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);
}
}
  • 然后在你需要解决这个问题的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文件中添加了这句话。

<item name="android:windowTranslucentNavigation">false</item>

注意: 你会发现系统报错,这是因为这句话是在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);

Android 适配底部返回键等虚拟键盘的完美解决方案的更多相关文章

  1. Android适配底部返回键等虚拟键盘的完美解决方案

    这个问题来来回回困扰了我很久,一直没能妥善解决. 场景1:华为手机遮挡了屏幕底部. 场景2:进入应用时,虚拟键自动缩回,留下空白区域. 需求: 需要安卓能自适应底部虚拟按键,用户隐藏虚拟按键时应用要占 ...

  2. Android监听返回键、Home键+再按一次返回键退出应用

    Android监听返回键需重写onKeyDown()方法 Home键keyCode==KeyEvent.KEYCODE_HOME @Override public boolean onKeyDown( ...

  3. android 监听返回键

    android监听返回键 public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE ...

  4. android点击返回键,如何做到不destory当前activity,只是stop。重新返回该activity的 时候可以直接使用,不需要创建新的activity实例

    问题描述,如题目: android点击返回键,顺序执行 pause,stop,destory. 以至于想重新进入这个activity的时候还要重新执行onCreate()方法,那么如何解决不再重新执行 ...

  5. android 点击返回键退出程序的方法

    android 点击返回键退出程序的方法 第一种: 再按一次返回键退出程序 private long exitTime = 0; @Override public boolean onKeyDown( ...

  6. Android应用中返回键的监听及处理

    MainActivity: package com.testnbackpressed;  import android.os.Bundle;  import android.view.KeyEvent ...

  7. Android 监听返回键、HOME键

    拦截返回键,HOME键,继承BaseActivity即可 import android.app.Activity; import android.content.BroadcastReceiver; ...

  8. cocos2d-x在android中响应返回键编译报错的bug分析

    先看一段代码如何在Android中加入返回按键的响应 <span style="font-size:18px;">自己派生CCKeypadDelegate的子类,然后注 ...

  9. 从网页监听Android设备的返回键

    最近搞Android项目的时候,遇到一个比较蛋疼的需求,需要从Client App调用系统浏览器打开一个页面,进行杂七杂八的一些交互之后,返回到App.如何打开浏览器和如何返回App这里就不说了,有兴 ...

随机推荐

  1. matlab形态学图像处理之strel函数

    转自:http://blog.sina.com.cn/s/blog_b1cd5d330101pmwi.html strel--structuring element 运用各种形状和大小构造元素,基本语 ...

  2. 反射-Class

    package classes; public class ClassDemo1 { public static void main(String[] args){ Foo foo1 = new Fo ...

  3. 在VS中对WCF服务进行更新,但是配置文件没有更新解决办法

    取消下面的勾选框

  4. Http协议-报文

    2013的双12即将到来,网上购物是大家所熟悉的.看中小米电视时,可以先下订单然后再付款,电商根据订单将小米电视正确安全的送达给我们.包裹包含电视的基本信息及电视的使用说明书,使我们能够初步的了解它的 ...

  5. Jdk 1.7*安装并配置

    jdk 1.7的下载,见http://www.cnblogs.com/lchzls/p/6281448.html 新建JAVA_HOME指明JDK安装路径,就是刚才安装时所选择的路径C:\Progra ...

  6. Photoshop学习:打开PS之前需要...

    颜色:色相(色彩名称):赤橙黄... H 色彩饱和度(纯度):?% S 明度(明暗):B HSB:人眼所看到的 拾色器 色相环 中间亮 边缘饱和度 黑颜色无色相,灰度有 光的三原色:红绿蓝(RGB) ...

  7. UGUI CanvasGroup

    说明,这种直接设置alpha的方法跟go的setActive(false)性能差不多,只少了激活和冻结冻结调用 http://blog.csdn.net/qq_28824335/article/det ...

  8. Centos下磁盘管理的常用命令记录(如查找大文件)

    Centos下磁盘管理的常用命令记录 查看系统磁盘空间占用,使用命令: df -h 结果: 查看磁盘inode使用情况,如果inode用完了,磁盘就没法写入新的内容了: df -i 结果: 如何查找磁 ...

  9. IBM Websphere MQ常用命令及常见错误

    MQSC: MQ Script Command  (不区分大小写) 注明: 下面命令行中的队列管理器名字,队列名字分别用QmgrName, QName替代. 下面标蓝色的,都需要根据实际配置更改! 打 ...

  10. Centos下安装pip失败或新装

    Centos安装pip失败: [root@localhost /]# yum -y install pip已加载插件:fastestmirrorRepodata is over 2 weeks old ...