快速解决Android适配底部返回键等虚拟键盘的问题

作者:NicolaAndMartin 时间:2021-10-25 14:50:23 

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

场景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);

来源:https://blog.csdn.net/c15522627353/article/details/52452490

标签:Android,返回键,虚拟,键盘
0
投稿

猜你喜欢

  • Java实现获取指定个数的不同随机数

    2023-11-14 21:42:34
  • Java递归遍历树形结构的实现代码

    2021-11-15 19:51:59
  • C#中数组初始化与数组元素复制的方法

    2023-05-14 15:45:06
  • Java多线程工具篇BlockingQueue的详解

    2022-07-03 20:47:56
  • java针对电话号码正则匹配实例

    2023-07-15 05:49:32
  • Spring RabbitMQ死信机制原理实例详解

    2022-04-29 18:52:18
  • SpringBoot中 Jackson 日期的时区和日期格式问题解决

    2021-09-06 19:37:50
  • Java设计模式之职责链模式详解

    2023-01-26 21:16:26
  • C#实现工厂方法模式

    2023-12-10 05:17:37
  • 在Struts2中如何将父类属性序列化为JSON格式的解决方法

    2022-08-01 09:30:34
  • C#实现微信红包功能

    2023-11-30 02:49:51
  • SpringMVC实现文件上传和下载功能

    2022-10-03 18:22:27
  • Java二分查找算法实现代码实例

    2023-08-24 05:34:23
  • Javaweb基础入门HTML之table与form

    2022-11-28 16:09:16
  • springboot 返回json格式数据时间格式配置方式

    2023-12-17 23:27:10
  • Android使用onCreateOptionsMenu()创建菜单Menu的方法详解

    2023-05-13 06:21:01
  • Spring中校验器(Validator)的深入讲解

    2022-03-05 11:58:35
  • 基于JWT的spring boot权限验证技术实现教程

    2022-07-20 01:48:58
  • java实现秒表功能

    2023-07-06 05:55:13
  • Mybatis中如何进行批量更新(updateBatch)

    2022-10-11 13:42:00
  • asp之家 软件编程 m.aspxhome.com