Android 软键盘的显示和隐藏,这样操作就对了
一、前言
如果有需要用到输入的地方,通常会有需要自动弹出或者收起软键盘的需求。开篇明义,本文会讲讲弹出和收起软键盘的一些细节,最终还会从源码进行分析。
想要操作软键盘,需要使用到 InputMethodManager ,它是一个系统服务,可以使用 Context.getSystemService()
获取到它。而很多关键的逻辑代码,都是在 InputMethodManagerService 中实现的。
特别说明:本文的所有分析的源码,都是基于 Android 26 的源码。
二、操作软键盘
2.1 InputMethodManager
前面提到,想要操作软键盘,需要使用 InputMethodManager ,它是一个系统服务,想要获取它,可以使用 getSystemService()
,获取到它。
毕竟是系统服务,使用的时候为了安全,还是要判空,避免空指针。
2.2 显示软键盘
在 InputMethodManager 中,有两个方法 showSoftInput()
和 showSoftInputFromInputMethod()
,而实际上,只有 showSoftInput()
是有效的。
它有两个重载方法,而通常我们会使用它的两个参数的方法。
这里我们只需要传递两个参数。它首先需要一个 View ,使用软键盘就是为了输入,而输入就需要有接收输入内容的 View ,这里接收输入的 View ,最好是一个 EditText(但这不是必须的)。
而第二个参数 flags 就是个标志位,从上面截图的方法签名上的文档上可以看到,它接收 0 或者 SHOW_INPYT_IMPLICIT 两个参数,但是实际上,它有第三个参数,另外一个是 SHOW_FORCED。
可以看到 1、2 都是有特殊含义的,实际上它们并不影响显示,只是在隐藏的时候,会有一些限制,这些后面看源码的时候再说,一般没有特别需要的话,我们直接传递 0 就好了。
现在,简单总结一下调用 showSoftInput()
会生效的关键点:
1、第一个参数,最好是 EditText 或者它的子类。
考虑到软键盘就是为了输入,EditText 就是一个接收输入的控件。而这不是绝对的,如果不是一个 EditText ,就必须要求这个 View 有两个属性,分别是:android:focusable="true"
和android:focusableInTouchMode="true"
。
2、第一个参数,必须是可获取焦点的,并且当前已经获取到焦点。
EditText 默认是允许获取焦点的,但是假如布局中,存在多个可获取焦点的控件,就需要提前让我们传递进去的 View 获取到焦点。获取焦点可以使用 requestFocus()
方法。
3、布局必须加载完成。
在 onCreate()
中,如果立即调用 showSoftInput()
是不会生效的。想要在页面一启动的时候就弹出键盘,可以在 Activity 上,设置 android:windowSoftInputMode
属性来完成,或者做一个延迟加载,View.postDelayed()
也是一个解决方案。
所以最终,完整的显示软键盘的代码就如下所示了。
2.3 隐藏软键盘
虽然 showSoftInput()
方法是有效的,但是想要隐藏软键盘,就没有提供对应的 hideSoftInput()
方法,但是却有一个 hideSoftInputFromWindow()
方法,可以用来隐藏软键盘。
先来看看这个方法的签名,它同样有两个方法可以调用。
它接收两个参数,第一个参数是一个 IBinder ,可以直接传递一个 View.getWindowToken()
的 windowToken 对象就可以了。而第二个参数,就是隐藏软键盘的标志位,如果没有特殊要求的话,直接传递 0 就好了。
注意这里虽然原则上需要传递一个之前弹出键盘传递的时候,传递的 View 的 windowToken ,但是实际情况是你只需要传递一个存在于当前布局 ViewTree 中,随意一个 View 的 windowToken 就可以了。
最终隐藏软件的代码就是这样的。
2.4 切换键盘的弹出和隐藏
在 InputMethodManager 中,还提供了一个 toggleSoftInput()
方法,如同它的名字一样,它可以让软键盘在显示和隐藏之间切换。
该方法,接收两个 flags ,分别是控制 show 和 hide 时候的标识,它们的含义和前面介绍的 showSoftInput()
和 hideSoftInputFromWindow()
一致,所以没有特殊要求,直接传递 0 就好了。
toggleSoftInput()
方法不要求传递一个 View 或者 windowToken,所以它并没有 showSoftInput()
中的一些限制,但是依然还有需要在布局绘制完成之后调用才会有效果。
虽然这个方法,限制很少,但是我们基本上不会使用它。主要原因在于,它是一个开关的方法,会根据当前的状态做相反的操作。这就导致很多时候,我们在代码中,无法直接根据 InputMethodManager 提供的方法判断当前软键盘的显示状态,这样也就无法确定调用它的时候的效果了。
三、源码分析
3.1 flag 的细节
前面的一些方法,都需要传递一个 flag 值,文档中描述的并不详细,我们就从源码的角度,来分析一下这些 flag 的含义。
先来看看 showSoftInput()
方法。
它最终会调用 mService.showSoftInput()
方法,最终的源码,就需要查看 InputMethodManagerService 中的代码了。而 showSoftInput()
方法,最终会调用 showCurrentInputLocked()
。
这个方法的代码很长,我们只关心和 flag 相关的代码。
可以看到,flag 会影响两个字段,mShowExplicitlyRequested 和 mShowForced,而 SHOW_FORCED 会更强势一点。
hideSoftInputFromWindow()
方法,最终也会调用 InputMethodManagerService 中的 hideCurrentInputLocked()
方法。
从 DEBUG == true
会输出的 Log 中,已经可以看到含义了。这里会根据显示和隐藏传递的两个 flag 来进行比对,也就是说,如果 flag 使用不正确,可能导致这里直接返回 false ,从而无法隐藏软键盘,这些细节对照代码就清晰了,就不在文章里屡这些细节了。
所以这就是为什么前面提到,如果没有特殊要求,直接传递 0 就好了,可以规避这个限制。
3.2 如何判断软键盘是否弹出
既然 toggleSoftInput()
可以根据当前软键盘的状态,进行不同的操作,那么肯定是有办法确定当前软键盘的状态的。
那我们继续追踪 toggleSoftInput()
的方法源码。
该方法,最终会调用到 InputMethodService 的 onToggleSoftInput()
方法。
在这个方法中,是根据 isInputViewShow()
方法来判定当前软键盘是否处于显示弹出的状态。但是我们并没有办法,直接和 InputMethodService 进行交互,我们也就没办法直接拿到当前键盘是否显示。
如果想要监听键盘的弹出和收起,可以使用 ViewTreeObserver.OnGlobalLayoutListener 这个监听,来监听布局的调整,从而判断出键盘的弹出和隐藏。这些细节有时间再聊。
四、KeyboardUtils
既然已经清楚了软键盘的收起和弹出的方法细节,那我们来写一个帮助类,来解决这个问题。让你们拿到就可用。
这里提供一下 Java 版和 Kotlin 版。
4.1 Java 版
public class KeyboardUtils {public static void showKeyboard(View view) {InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);if (imm != null) {view.requestFocus();imm.showSoftInput(view, 0);}}public static void hideKeyboard(View view){InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);if (imm != null) {imm.hideSoftInputFromWindow(view.getWindowToken(),0);}}public static void toggleSoftInput(View view){InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);if (imm != null) {imm.toggleSoftInput(0,0);}}
}
复制代码
4.2 Kotlin 版
object KeyboardktUtils{fun showKeyboard(view: View) {val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManagerif (imm != null) {view.requestFocus()imm.showSoftInput(view, 0)}}fun hideKeyboard(view: View) {val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManagerimm?.hideSoftInputFromWindow(view.windowToken, 0)}fun toggleSoftInput(view: View) {val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManagerimm?.toggleSoftInput(0, 0)}
}
复制代码
今天在承香墨影公众号的后台,回复『成长』。我会送你一些我整理的学习资料,包含:Android反编译、算法、设计模式、虚拟机、Linux、Kotlin、Python、爬虫、Web项目源码。
推荐阅读:
- 认真聊聊阴影那些事儿
- 利用 StateListAnimator 为你的点击加个动画吧!
- 好的代码可以自己说话
- 关于如何编写 Clean Code 的 6 个简单技巧
- 手写你的第一个 Dalvik 版的 HelloWorld !
Android 软键盘的显示和隐藏,这样操作就对了相关推荐
- Android软键盘手动显示、隐藏、布局上移和EditText上移
主要实现:Android软键盘手动显示.隐藏.布局上移和EditText上移 AndroidManifest.xml <?xml version="1.0" encoding ...
- Android软键盘的显示与隐藏
本文仅是对原创文章重新进行或多或少的代码测试,权当记录并加深印象 再次感谢开发者社区的分享 一:简述 点击文本框EditText,系统会自动弹出软键盘(其本质是一个Dialog),这必然会引起当前Ac ...
- android 隐藏键盘时ui延迟恢复,android 软键盘的显示与隐藏问题的研究
在android中,常常会和输入法的软件键盘交互.在Manifest文件中,系统给activity的一个属性-windowSoftInputMode来控制输入法的显示方式. 该属性提供了Activit ...
- android 软键盘的显示和隐藏方法
方法一:在OnCreate()函数中,加上下面的代码 getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE ...
- android软键盘显现,Android软键盘的显示和隐藏
显示软键盘 //显示小键盘 public void showSoftKeyboard(View view, Context mContext) { if (view.requestFocus()) { ...
- android 软键盘监听、隐藏、显示、点击空白处隐藏和Android KEYCODE 键值大全
android 软键盘监听.隐藏.显示.点击空白处隐藏. textView.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boo ...
- 安卓如何调出软键盘_Android 软键盘的显示和隐藏,这样操作就对了
一.前言 如果有需要用到输入的地方,通常会有需要自动弹出或者收起软键盘的需求.开篇明义,本文会讲讲弹出和收起软键盘的一些细节,最终还会从源码进行分析. 想要操作软键盘,需要使用到 InputMetho ...
- 安卓如何调出软键盘_Android开发中软键盘的显示和隐藏
本篇内容通过操作软键盘的函数着手详细分析了隐藏或者显示软键盘的实现方法,并且对其中重要的代码做了详细分析. 一.开篇 如果有需要用到输入的地方,通常会有需要自动弹出或者收起软键盘的需求.开篇明义,本文 ...
- Android 检测键盘是否显示及隐藏键盘
Android 检测键盘是否显示及隐藏键盘的方法~~ package com.newland.util;import android.app.Activity; import android.view ...
最新文章
- 教你如何更优惠的购买阿里云服务器?
- iOS UIView成像流程
- 线性代数的本质 - 02 - 线性组合、张成的空间与基
- python判断文件是否为空文件对象_判断Python对象是不是为文件对象的方法有哪些...
- C++ Primer 5th笔记(10)chapter10 泛型算法 :lambda
- 华为2013校园招聘上机笔试题
- 1814: 一元三次方程求解
- sql server2008如何修改mac地址_如何查看本机的MAC地址和IP地址?
- 图像质量评价之数据库
- [转]UpdatePanel的用法详解
- python之路-08-集合
- Vue打包时报错:ReferenceError: primordials is not defined
- php友情链接代码,php友情链接
- 计算机网络数据传输的,计算机网络数据传输技术基本概念
- 基于树莓派的sht20温湿度传感器应用(c语言)
- 引用百度新闻热门搜索html,百度新闻搜索技巧(之一)
- 游戏开发中的进阶向量数学
- Facebook多账号运营如何防关联
- Bootstrap——制作个人简历网页、工具类【边框(添加、删除、颜色、圆角)、清除浮动、颜色(文本、链接、背景)、display属性、浮动、定位、文本对齐】
- 人类为什么不再登月了?
热门文章
- 用python实现的抓取腾讯视频所有电影的爬虫
- I.MX6 修改调试串口号(ttymx0 - ttymxc2)
- 终于恢复了珍惜多年的照片
- “金财工程”网络安全 五
- XPath实例教程十四、following-sibling轴
- + ,- (加号,减号) 是数字类型吗?(sql server 2000中)
- 在ECS上使用Windows “跨区卷”、“条带卷”讨论以及扩容操作
- openstack对接华为存储
- C语言基础知识【数据类型】
- 苹果大战FBI将加速科技圈的加密技术发展?