当前位置: 首页 > 编程笔记 >

基于界面适配华为手机的虚拟按键的解决方法

谷梁向荣
2023-03-14
本文向大家介绍基于界面适配华为手机的虚拟按键的解决方法,包括了基于界面适配华为手机的虚拟按键的解决方法的使用技巧和注意事项,需要的朋友参考一下

一、概述

在项目中,测试发现在一些华为手机的屏幕适配上出现了问题,主要是因为华为Mate等一些系列的手机有一个虚拟按键的设计。当这些虚拟按键由用户手势滑出,或默认显示的话,就会遮挡我们本身的应用布局。比如欢迎界面过后是四个Fragment,那么底部的四个tab就会被虚拟的导航栏遮住,非常难看。

当然,欢迎页的图片适配也同样会出现问题。

Google后得出第一个问题的解决方案。第二个图片的问题则用自己摸索的方式解决,当然也非常简单。

二、布局由于虚拟按键导致导航栏顶上去的解决方法

在我们的项目中加载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;
 }
}

重新测试,发现无论是否弹出虚拟按键,都不会再次遮挡tab按钮。

三、原理

上面的代码需要在setContentView后面执行。其最初的解决方案是stackoverflow上有人为了适配软键盘在全屏下的布局问题。

开始先判断该设备上是否存在导航栏。为什么用findViewById(android.R.id.content)呢?因为android.R.id.content这个id代表的就是所在页面的根布局,而并不需要特别指定一个id给该布局。可以通过调用系统API返回的结果,也可以通过判断该手机是否为华为手机,操作系统属于哪种类型来来判断。

一旦确定该设备存在导航栏,将对该布局进行重新测量。首先mChildOfContent得到其视图树,对全局高度实现监听。

OnGlobalLayoutListener 是ViewTreeObserver的内部类,当一个视图树的布局发生改变时,可以被ViewTreeObserver监听到,这是一个注册监听视图树的观察者(observer),在视图树的全局事件改变时得到通知。ViewTreeObserver不能直接实例化,而是通过getViewTreeObserver()获得。

接着得到视图目前可用的总高度,将其赋值给mChildOfContent的布局高度。调用requestLayout,让mChildOfContent要求自己的parent view对自己重新设置位置。

四、全屏图片的适配

解决了布局的问题,再来看欢迎页启动时候全屏图片的适配问题。发现该方法对于图片不适用。如下图,当虚拟按键弹出时,图片照样被遮挡了底部的一小部分。

如果隐藏虚拟按键,图片大小恢复正常

仔细想想,对于一个ImageView直接占据一个layout的情况,是没有必要再去写一些代码进行适配的。到布局里一看,发现ImageView的属性 android:scaleType=”centerCrop”

将其改为 android:scaleType=”fitXY”就可以解决了。这样图片可能高度会随着虚拟键的弹出而压缩,但是很好的适配了布局高度的变化而不会被遮挡。

关于scaleType的详细介绍,留待其他文章里再探讨。

以上这篇基于界面适配华为手机的虚拟按键的解决方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文档说明了如何使用基于域名的虚拟主机。 基于域名的虚拟主机和基于IP的虚拟主机比较 基于IP的虚拟主机使用连接的IP地址来决定相应的虚拟主机。这样,你就需要为每个虚拟主机分配一个独立的IP地址。而基于域名的虚拟主机是根据客户端提交的HTTP头中标识主机名的部分决定的。使用这种技术,很多虚拟主机可以共享同一个IP地址。 基于域名的虚拟主机相对比较简单,因为你只需要配置你的DNS服务器将每个主机名映

  • 本文向大家介绍快速解决Android适配底部返回键等虚拟键盘的问题,包括了快速解决Android适配底部返回键等虚拟键盘的问题的使用技巧和注意事项,需要的朋友参考一下 这个问题来来回回困扰了我很久,一直没能妥善解决。 场景1:华为手机遮挡了屏幕底部。 场景2:进入应用时,虚拟键自动缩回,留下空白区域。 需求: 需要安卓能自适应底部虚拟按键,用户隐藏虚拟按键时应用要占满整个屏幕,当用户启用虚拟键时,

  • 本文向大家介绍虚拟机ubuntu16.04无法连网的解决方法,包括了虚拟机ubuntu16.04无法连网的解决方法的使用技巧和注意事项,需要的朋友参考一下 刚安装玩Ubuntu,打开后上网没有网络连接 ,点击右上角的数据连接,显示已经启动联网,但是用火狐还是无法上网。 解决方法如下:  先查看虚拟机的网络适配器:点击虚拟机左上角的编辑,里面有个网络适配器 然后再进入编辑虚拟机设置,看过上一篇安装U

  • 系统需求 就像它的名字"基于IP"所暗示的那样,这样的服务器中每个基于IP的虚拟主机必须拥有不同的IP地址。可以通过配备多个真实的物理网络接口来达到这一要求,也可以使用几乎所有流行的操作系统都支持的虚拟界面来达到这一要求(详情请参见您的系统文档,这种功能一般被称作"IP别名",一般用"ifconfig"命令来进行设置)。 如何配置Apache 有两种配置方法来使apache支持多主机:为每个虚拟主

  • 本文向大家介绍基于编译虚拟机jvm—openjdk的编译详解,包括了基于编译虚拟机jvm—openjdk的编译详解的使用技巧和注意事项,需要的朋友参考一下 java只所以被推广,实际上很大原因是因为本身是跨平台的,很大作用是因为虚拟机的关系。 一般情况下开发人员不需要关注虚拟机内部实现就可以日常开发了,但是有时候涉及到性能的时候就需要了解虚拟机的实现机制了。 那么今天写的内容更多的是关于编译一套自

  • 本文向大家介绍win10 apache配置虚拟主机后localhost无法使用的解决方法,包括了win10 apache配置虚拟主机后localhost无法使用的解决方法的使用技巧和注意事项,需要的朋友参考一下 win10系统配置虚拟主机 1.用记事本或Sublime Text打开httpd.conf ctrl + f 搜索httpd-vhosts.conf 将 #Include conf/ext