本文转载自:https://blog.csdn.net/l540675759/article/details/74528641

背景

1.Android软键盘这块从我入职到现在,是一个一直纠缠我的问题。

2.从布局挤压,到EditText显示不全,在到弹出时卡顿,在Android软键盘面前我无数次跌倒。

3.因为网上大多数的知识点比较分散而且很杂,所以本篇做一个整合篇。

4.Android软键盘这块知识点比较密集,了解过一次之后,差不多什么情况都可以找到原因了。

5.感谢Android软键盘的问题,从我入职陪伴我到现在,让我一个一个不停的解决。


前言

本文将从以下几个方面进行介绍:

(1)InputMethodService的源码解析,从源码解读中告诉你为什么软键盘弹出的是一个Dialog(2)Android软键盘显示时,设置windowSoftInputMode的作用(3)EditText设置imeOptions属性对软键盘的影响(4)软键盘上面的按键监听(5)横屏状态下,不希望软键盘显示全屏怎么处理(6)控制软键盘的弹出和关闭的方法(7)EditText在软键盘弹出的时候显示不全,怎么获取软键盘弹出和关闭的监听(8)软键盘弹出的时候,造成页面卡顿,这时候如何发现问题并解决问题

Android软键盘的显示原理

软键盘其实是一个Dialog    InputMethodService为我们的输入法创建了一个Dialog,并且对某些参数进行了设置,使之能够在底部或者全屏显示。当我们点击输入框时,系统会对当前的主窗口进行调整,以便留出相应的空间来显示该Dialog在底部,或者全屏。    其实这段话我们经常在各种软键盘博客所看到,但是大家并不知道Android是怎么为我们创建的这个Dialog,所以我先带大家来看下软键盘生成这块的源码,了解软键盘的生成流程。


InputMethodService的源码解析

我们先来看一下InputMethodService的继承关系:
因为InputMethodService属于服务,接下来我们先看一下服务的入口onCreate()方法:
    @Override public void onCreate() {//设置主题与xml里面设置theme是一样的道理mTheme = Resources.selectSystemTheme(mTheme,getApplicationInfo().targetSdkVersion,android.R.style.Theme_InputMethod,android.R.style.Theme_Holo_InputMethod,android.R.style.Theme_DeviceDefault_InputMethod,android.R.style.Theme_DeviceDefault_InputMethod);super.setTheme(mTheme);//创建InputMethodManangermImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);mSettingsObserver = SettingsObserver.createAndRegister(this);mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);/*** 这里注意一下,首先这里的命名属于Window,然后我们发现了Gravity.BOTTOM,就更加确定了这个就是* 软键盘所创建的Dialog对象*/mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);if (mHardwareAccelerated) {mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);}initViews();mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);}通过上面的分析,我们怀疑这里的SoftInputWindow是软键盘弹出创建的Dialog对象,下面我们看下SoftInputWindow的源码。
public class SoftInputWindow extends Dialog{....
}

stateUnspecified-不指定软键盘的状态(隐藏还是可见) 将由系统选择合适的状态,或依赖主题中的设置,这是对软键盘行为的默认设置

stateUnchanged-保留状态 当 Activity 转至前台时保留软键盘最后所处的任何状态,无论是可见还是隐藏

stateHidden-隐藏软键盘 当用户确实是向前导航到 Activity,而不是因离开另一Activity 而返回时隐藏软键盘

stateAlwaysHidden-始终隐藏软键盘 当 Activity 的主窗口有输入焦点时始终隐藏软键盘

stateVisible-显示软键盘 在正常的适宜情况下(当用户向前导航到 Activity 的主窗口时)显示软键盘

stateAlwaysVisible-显示软键盘 当用户确实是向前导航到 Activity,而不是因离开另一Activity 而返回时.

(2)在软键盘弹出时,是否需要Activity对此进行调整

还是同样的操作,点击最下面的EditText13

(1)设置windowSoftInputMode为adjustNoting

我们可以看出,当点击EditText12时,弹出软键盘将主窗口下半部分给遮盖,并且主窗口没有做出任何反应,和不加ScrollView是一样的情况。

(2)设置windowSoftInputMode为adjustResize

我们可以发现,当设置其属性为adjustResize时,当软键盘弹出时,ScrollView会重新绘制,然后滚动EditText13位置,使其显示在软键盘之上。

(3)设置windowSoftInputMode为adjustUnspecified

当设置其属性为默认属性adjustUnspecified时,可以发现在添加了ScrollView控件时,布局的窗口并不会上移(这个观察Toolbar就可以发现),而通过重绘ScrollView,让其滚动到最低端,并且给软键盘流出控件,而这个表现即和adjustResize完全一致。

(4)设置windowSoftInputMode为adjustPan

可以发现,在滑动空间下,设置属性adjustPan时,依旧会将主窗口上移,来使EditText13显示在软键盘之上,可以通过观察Toolbar得知。

windowSoftInputMode总结

通过上面的例子,我们可以完全理解adjust系列的各个参数的作用。而软键盘的显示和隐藏这里面需要并不多,而且内容并不算复杂,大家回去自己尝试下就可以。


EditText设置imeOptions属性对软键盘的影响

在日常开发中,如果需要将软键盘的Enter键更改为其他键,可以设置其android:imeOptions 属性,这个属性可以控制软键盘的Enter键,以及横屏情况下的软键盘显示状态。

该设置必须是下面所列的值之一,或者是一个“action…”值加上一个“flag…”值的组合,在action…组中设置多个值(例如,多个“action…”值)都会产生未定义结果,而flag….可以设置多个。各值之间使用垂直条 (|) 分隔

(1)控制软键盘上的Enter键
  • 1

android:imeOptions=”normal”

当android:singleLine=”true”
输入框后面还有输入控件的时候会显示next,没有时会显示done(完成)
当android:singleLine=”false”
输入框会进行换行操作

android:imeOptions=”actionUnspecified”

该属性为默认属性,一般情况下为“normal”的使用情形。

android:imeOptions=”actionNone”

显示回车键,当singleLine为true的时候,会跳到下个可输出的控件,否则软键盘消失,输入完毕。

android:imeOptions=”actionGo”

显示为Go(前往)按钮,需要配合android:singleLine使用,否则为回车键起换行作用,并且需要自己写事件。

android:imeOptions=”actionSearch”

显示搜索(Search)按钮,需要配合android:singleLine使用,否则为回车键起换行作用,并且需要自己写事件。

android:imeOptions=”actionSend”

显示send(发送)按钮,需要配合android:singleLine使用,否则为回车键起换行作用,并且需要自己写事件。

android:imeOptions=”actionNext”

显示next(下一步)按钮,作用是跳到下一个可输入的控件,需要配合android:singleLine使用,否则为回车键起换行作用。

android:imeOptions=”actionDone”

显示done(完成)按钮,作用编辑完成,让软键盘消失.需要配合android:singleLine使用,否则为回车键起换行作用。

android:imeOptions=”actionPrevious”

显示上一步按钮,如果前面有输入控件,点击后会回到前一个控件获取焦点,.需要配合android:singleLine使用,否则为回车键起换行作用。

可能各个输入法的显示图标不一样,但是效果是一样的,这里用的是搜狗输入法。

(2)横屏下控制软键盘

而如果对于这一块有什么不明白的,可以参考这篇博客。

Android手动显示和隐藏软键盘方法总结

实际案例3:EditText显示不全,并且需要监听软键盘弹出和关闭

现在有一个常见的需求,EditText被布局包裹,然后需要将原生的EditText背景给替换掉或者直接设置为null(或者其他),然后和布局上下存在间距,然后整体与底部对齐。

这时候弹出软键盘,请看图:

从图中可以发现,当原生的EditText背景被替换之后,软键盘会遮盖掉自定义区域,并且直接显示在EditText之下,正常情况下,我们是希望软键盘显示在整个外层的Layout之下的。

当时对于这个问题,我没有头绪好一阵子,现在来看,那时候挺年轻的。

而这个问题,就属于软键盘遮挡布局的问题:

引用块内容

(1)软键盘遮盖焦点:

当软键盘弹出的时候,将EditText等输入类的控件的焦点遮盖时,这时候可以设置adjustPan或者adjustResize可以很好的解决。

这里如果理解好本博文第一块内容就能很好解决这个问题。

(2)软键盘遮盖没有遮盖焦点,但是遮盖了需要显示的控件:

这时候设置通过设置属性adjustPan或者adjustResize还不足以解决问题,因为软键盘并没有遮盖了EditText的焦点,所以单独设置这两个属性是对软键盘或者界面是无法产生改变的。

这时我们必须从另外一个角度来考虑这个问题,就是来监听软键盘的弹出和关闭来操作布局,来解决这个问题。

这时候普遍会有以下的几种解决方案:

(1)设置adjustResize属性,当软键盘弹出的时候会重绘布局,然后设置根布局的OnLayoutChangeListener的监听,来监听布局的变化。

 mScrollView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {@Overridepublic void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {Log.d("new change ", "left : " + left + "top : " + top + "right : " + right + "bottom : " + bottom);Log.d("old change ", "oldLeft : " + oldLeft + "oldTop : " + oldTop + "oldRight : " + oldRight + "oldBottom : " + oldBottom);}});//当软键盘弹出
07-09 21:16:22.911 23653-23653/com.xiucai.softdemo D/new change: left : 0top : 0right : 1080bottom : 817
07-09 21:16:22.911 23653-23653/com.xiucai.softdemo D/old change: oldLeft : 0oldTop : 0oldRight : 1080oldBottom : 1692//当软键盘关闭
07-09 21:16:44.457 23653-23653/com.xiucai.softdemo D/new change: left : 0top : 0right : 1080bottom : 1692
07-09 21:16:44.457 23653-23653/com.xiucai.softdemo D/old change: oldLeft : 0oldTop : 0oldRight : 1080oldBottom : 817

上面代码是借鉴android 解决输入法键盘遮盖布局问题 这篇文章而来,目的让大家了解这种方式是怎么判断软键盘的弹出和隐藏。

里面需要平移的View,不一定是ScrollView,其他View也可,一般来说作为XML的根布局即可。

平常一般来说,我会使用这个工具类

package com.xiucai.common.manager;import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;import java.util.LinkedList;
import java.util.List;/*** Created by SuperD on 2017/5/12.*/public class SoftKeyBroadManager  implements ViewTreeObserver.OnGlobalLayoutListener{public interface SoftKeyboardStateListener {void onSoftKeyboardOpened(int keyboardHeightInPx);void onSoftKeyboardClosed();}private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();private final View activityRootView;private int lastSoftKeyboardHeightInPx;private boolean isSoftKeyboardOpened;public SoftKeyBroadManager(View activityRootView) {this(activityRootView, false);}public SoftKeyBroadManager(View activityRootView, boolean isSoftKeyboardOpened) {this.activityRootView = activityRootView;this.isSoftKeyboardOpened = isSoftKeyboardOpened;activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);}@Overridepublic void onGlobalLayout() {final Rect r = new Rect();//r will be populated with the coordinates of your view that area still visible.activityRootView.getWindowVisibleDisplayFrame(r);final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);Log.d("SoftKeyboardStateHelper", "heightDiff:" + heightDiff);if (!isSoftKeyboardOpened && heightDiff > 500) { // if more than 100 pixels, its probably a keyboard...isSoftKeyboardOpened = true;notifyOnSoftKeyboardOpened(heightDiff);//if (isSoftKeyboardOpened && heightDiff < 100)} else if (isSoftKeyboardOpened && heightDiff < 500) {isSoftKeyboardOpened = false;notifyOnSoftKeyboardClosed();}}public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {this.isSoftKeyboardOpened = isSoftKeyboardOpened;}public boolean isSoftKeyboardOpened() {return isSoftKeyboardOpened;}/*** Default value is zero (0)** @return last saved keyboard height in px*/public int getLastSoftKeyboardHeightInPx() {return lastSoftKeyboardHeightInPx;}public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {listeners.add(listener);}public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {listeners.remove(listener);}private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;for (SoftKeyboardStateListener listener : listeners) {if (listener != null) {listener.onSoftKeyboardOpened(keyboardHeightInPx);}}}private void notifyOnSoftKeyboardClosed() {for (SoftKeyboardStateListener listener : listeners) {if (listener != null) {listener.onSoftKeyboardClosed();}}}
}

最后如果感觉上面的方案不可行,Github也有一个现成方案,但是博主本人没试过,原理都是一样的。大家可以自行取舍。

Github软键盘监听的工具类

知乎上讨论软键盘的文章


实际案例4: 软键盘弹出来卡顿,找不到原因?

正常来说博文实差不多到这里就应该结束了,但是博主在实际开发中,也会遇到一些诡异的现象,例如软键盘弹出卡顿,但是这种情况下,根本无法定位到卡顿原因。

博主遇到这个问题时,怀疑了设置属性错误,怀疑了线程XX没关,怀疑了布局太过于复杂,总之该想的博主都想了,但是无论怎么试都是徒劳的。

因为博主犯了一个大错

在没找到原因之前,胡乱猜测,可能是这块?是不是那个的问题,而不确定问题的来源这个问题我感觉大家都会遇到,不从事情的本质上下手,这样会多花很多时间用在无用的地方,使自己的开发效率很低。

推荐一款检测卡顿的神器BlockCanary

还原下我当时遇到的问题:

当时我在做一个直播间的功能,直播间从主页跳转进入的,给大家截一张图,大家就懂了。

当时做直播间其他功能的时,发现直播间软键盘在弹出和关闭的时候卡顿。

当时怀疑:

(1)什么动画没停,什么线程没关。

(2)软键盘 弹出的时候是不是加载的布局太多.

(3)直播间的布局太过于复杂,导致软键盘弹出时绘制卡顿。

在长期的测试发现一个现象,就是在高端机型上这种状态不明显,而在底端机型问题比较严重,有时候弹出软键盘卡顿很长时间。

过了半个月博主思路换了,想想软键盘弹出卡顿,能不能从卡顿原因下手,来解决问题,后来找到了BlockCanary,接入使用后发现:

原因:
竟然是 主页在软键盘每次弹出或者关闭的时候重新绘制.因为当时BlockCanary当时指向主页的RecyclerView重绘,我当时想是不可能的.
  • 最后,博主凭直觉认为和主页SingleTask有关,因为没有确切的理由,这里只是提出自己的观点,而最后问题也解决了。

    如果没有BlockCanary我永远发现不了,卡顿的原因是在看不见的主页。

    后来我给主页设置成adjustNothing因为主页不需要弹出软键盘。


    实际案例5:Android键盘面板冲突,布局闪动的解决方法

    这个问题是我在找Android软键盘相关的问题的时候发现的,这块我也没遇到这个问题,所以给大家两个相关的介绍的地址,希望能对大家有帮助。

    解决Android软键盘,布局闪动的相关博文

    解决Android软键盘布局闪动的Demo

    开源的Android软键盘布局闪动的解决方案


    总结

    (1)第一次写这么长的博客,感觉会有一些不足,各位看官如果有不合理的地方,或者有误的地方请直接指出。

    (2)本来想整理成一个Demo的,后来简单看来下,该有的几乎都贴出来了,有需要的可以按需复制就可以。

    (3)写完这篇博客之后,感觉博客干货还是不多,所以定位这篇文章算是总结性质加上实际案例性质的博客。

    (4)Android软键盘的总结就差不多到这里,希望各位看官,如果看到这里有收获,就点点赞,灌灌水,顶一波,这样博主才有写下去的动力。

    (5)感谢小辉同学的校验,调整了文章中不通顺的地方。


    参考文档

    1.彻底搞定Android开发中软键盘的常见问题
    http://blog.csdn.net/mynameishuangshuai/article/details/51567357
    2.Android UI(EditText)详解
    http://blog.csdn.net/qq_28057577/article/details/51919965?locationNum=12&fps=1
    3.微信软键盘布局闪动问题
    https://blog.dreamtobe.cn/2015/09/01/keyboard-panel-switch/
    

Android软键盘的全面解析,让你不再怕控件被遮盖相关推荐

  1. edittext 软键盘上方_Android 软键盘的全面解析,让你不再怕控件被遮盖

    原标题:Android 软键盘的全面解析,让你不再怕控件被遮盖 作者 | Vander丶 编辑 | 苏宓 微信公众号 | mobilehub 背景 Android软键盘这块从我入职到现在,是一个一直纠 ...

  2. android 页面默认不弹软键盘_Android 软键盘的全面解析,让你不再怕控件被遮盖!...

    作者 | Vander丶 编辑 | 苏宓 微信公众号 | mobilehub 背景 Android软键盘这块从我入职到现在,是一个一直纠缠我的问题. 从布局挤压,到EditText显示不全,在到弹出时 ...

  3. Android 软键盘的全面解析,让你不再怕控件被遮盖

    博客地址:http://blog.csdn.net/l540675759/article/details/74528641 博客地址:https://blog.csdn.net/wangwangli6 ...

  4. Android软键盘遮挡EditText问题

    最近在调试App过程遇到软件盘遮挡EditText的问题,特记录下问题的解决过程 在4.4版本上,如果EditText设置了gravity="center|right"其中之一且同 ...

  5. Android 软键盘显示隐藏判断

    Android软键盘始终感觉是个BUG,难缠 用起来不顺手,每次应用版本涉及到相关问题,总是很尴尬 只能静下心好好梳理一下 1. 软键盘显示原理 软键盘的本质是什么?软键盘其实是一个Dialog In ...

  6. Android开发笔记(三十六)展示类控件

    View/ViewGroup View是单个视图,所有的控件类都是从它派生出来:而ViewGroup是个视图组织,所有的布局视图类都是从它派生出来.由于View和ViewGroup是基类,因此很少会直 ...

  7. android 软件盘未弹出如何获取高度,Android 软键盘的那些坑,一招搞定!

    3 软键盘高度获取 对于上面的问题1,既然想要EditText单独顶上去,那么就需要知道当前键盘弹出的高度,再设置EditText坐标即可. 问题的关键转变为如何获取键盘的高度. Activity窗口 ...

  8. Android软键盘遮挡的四种解决方案

    Android软键盘遮挡的四种解决方案 参考文章: (1)Android软键盘遮挡的四种解决方案 (2)https://www.cnblogs.com/jerehedu/p/4194125.html ...

  9. Android 软键盘弹出时布局内指定内容上移实现及问题解决

    Android 软键盘弹出时布局内指定内容上移实现及问题解决 参考文章: (1)Android 软键盘弹出时布局内指定内容上移实现及问题解决 (2)https://www.cnblogs.com/as ...

最新文章

  1. 企业的7种工作管理最佳实践
  2. sap服务器应用webservice加载spring的机制问题
  3. 迷你HTM在线L编辑器—xhEditor
  4. Java并发教程– CountDownLatch
  5. java内部类练习题,学习笔记——Java内部类练习题
  6. 互联网晚报 | 1月15日 星期六 | 娃哈哈董事长称准备6亿发年终奖;河南省消协对辛巴提起公益诉讼;支付宝上线消息“刷子”功能...
  7. Android使用的工具类
  8. 【报告分享】2020企业精细化运营白皮书.pdf(附下载链接)
  9. 六年级下册百分数计算题_六年级数学上册期末试卷(附答案)
  10. python练习题及答案-听说你python基础入门了?100个经典练习题送给你(附完整答案)...
  11. php去掉 部分字符,输出,php如何去除某个字符
  12. java编写一个方法printn_Java语言程序设计 基础篇 原书第10版 ,梁勇著 (第六章)编程练习题...
  13. cudnn下载速度很慢怎么解决
  14. Axure RP9 安装
  15. Scala下载和安装
  16. python打印九九乘法表上三角_用Python打印九九乘法表正三角和倒三角。
  17. 欲速则不达--不能忽略情绪
  18. Unity3D windows平台视频录制录屏插件 UnityRecorder
  19. FFmpeg 简单的视频播放例子(Qt)
  20. 2 OPENVINO : What is Video, what is computer vision, how do we accelerate it on modern computer

热门文章

  1. 全能编码器Mencoder(mencoder.exe)命令行用法
  2. linux 造字程序下载,truetype造字程序下载
  3. Simulink 环境基础知识(二十六)--信号基础知识
  4. 为什么学习Linux系统?
  5. Python 用于电路课程
  6. 全球隔离,生出不少坏毛病
  7. 到微软下载VS2008
  8. python 输出纯音频_提取视频中的音频python三行程序搞定
  9. fiddler对浏览器、app抓包及证书安装
  10. 一个光子的能量是多少?