Android 软键盘相关问题

1. windowSoftInputMode属性的使用

Android使用windowSoftInputMode来控制Activity 的主窗口与包含屏幕软键盘的窗口的交互方式。 该属性的设置影响两个方面:

  • 当 Activity 成为用户注意的焦点时软键盘的状态 — 隐藏还是可见。
  • 对 Activity 主窗口所做的调整 — 是否将其尺寸调小以为软键盘腾出空间,或者当窗口部分被软键盘遮挡时是否平移其内容以使当前焦点可见。

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

<activity android:windowSoftInputMode="stateVisible|adjustResize" . . .复制代码

此处设置的值(“stateUnspecified”和“adjustUnspecified”除外)替换主题中设置的值。

说明
"stateUnspecified"不指定软键盘的状态(隐藏还是可见)。 将由系统选择合适的状态,或依赖主题中的设置。这是对软键盘行为的默认设置。
“stateUnchanged”当 Activity 转至前台时保留软键盘最后所处的任何状态,无论是可见还是隐藏。
“stateHidden”当用户选择 Activity 时 — 也就是说,当用户确实是向前导航到 Activity,而不是因离开另一 Activity 而返回时 — 隐藏软键盘。
“stateAlwaysHidden”当 Activity 的主窗口有输入焦点时始终隐藏软键盘。
“stateVisible”在正常的适宜情况下(当用户向前导航到 Activity 的主窗口时)显示软键盘。
“stateAlwaysVisible”当用户选择 Activity 时 — 也就是说,当用户确实是向前导航到 Activity,而不是因离开另一 Activity 而返回时 — 显示软键盘。
“adjustUnspecified”不指定 Activity 的主窗口是否调整尺寸以为软键盘腾出空间,或者窗口内容是否进行平移以在屏幕上显露当前焦点。 系统会根据窗口的内容是否存在任何可滚动其内容的布局视图来自动选择其中一种模式。 如果存在这样的视图,窗口将进行尺寸调整,前提是可通过滚动在较小区域内看到窗口的所有内容。这是对主窗口行为的默认设置。
“adjustResize”始终调整 Activity 主窗口的尺寸来为屏幕上的软键盘腾出空间。
“adjustPan”不调整 Activity 主窗口的尺寸来为软键盘腾出空间, 而是自动平移窗口的内容,使当前焦点永远不被键盘遮盖,让用户始终都能看到其输入的内容。 这通常不如尺寸调正可取,因为用户可能需要关闭软键盘以到达被遮盖的窗口部分或与这些部分进行交互。

系统默认值为:stateUnspecified|adjustUnspecified

上述是引用android官方文档的说明,但是这个并不能让我们理解所有内容。因此本次将具体探究这9个属性是如何影响。

1. stateUnspecified

android官方描述为:不指定软键盘的状态(隐藏还是可见)。 将由系统选择合适的状态,或依赖主题中的设置。这是对软键盘行为的默认设置。哪系统认为的合适的状态是什么样的呢?

我们采用如下布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content" />
</LinearLayout>复制代码

我们发现软键盘没有自动弹出,需要手动点击EditText后,键盘才会弹出来。
如果采用如下布局


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content" /></ScrollView>
</LinearLayout>复制代码

我们发现软键盘会自动弹出。这个就很奇怪了,为什么就加了一个ScrollView,难道是因为添加了ScrollView,软键盘就可以自动弹出来吗?我们看一下如下的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content" /></ScrollView>
</LinearLayout>复制代码

运行代码可以发现,这样软键盘也会不会自动弹出来。说明软键盘自动弹出和ScrollView没有直接关系。

如果我们采用如下布局,我们发现软键盘还是会自动弹出

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content" /><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="测试"android:id="@+id/btn_test"/></LinearLayout></ScrollView>
</LinearLayout>复制代码

如何依旧采用上述的布局,但是我们在onCreate中加上如下代码

    Button button= (Button) findViewById(R.id.btn_test);button.setFocusable(true);button.setFocusableInTouchMode(true);button.requestFocus();button.requestFocusFromTouch();复制代码

我们发现软键盘将不会自动弹出来。

现在我们总结一下,当属性设置为stateUnspecified时,系统默认时不会自动弹出软键盘,但是当界面上有滚动需求时(有ListView或ScrollView等)同时有获得焦点的输入框软键盘将自动弹出来(如果获得焦点不是输入框也不会自动弹出软键盘)。

2. stateUnspecified

这个比较简单,进入当前界面是否弹出软键盘由上一个界面决定。如果离开上一个界面,键盘是打开,那边该界面键盘就是打开;否则就是关闭的.

3. stateHidden

这个也比较简单,进入当前界面不管当前上一个界面或者当前界面如何,默认不显示软键盘。

4. stateAlwaysHidden

这个参数和stateHidden的区别是当我们跳转到下个界面,如果下个页面的软键盘是显示的,而我们再次回来的时候,软键盘就会隐藏起来。而设置为stateHidden,我们再次回来的时候,软键盘讲显示出来。

5. stateVisible

设置这个属性,进入这个界面时无论界面是否需要弹出软键盘,软键盘都会显示。

6. stateAlwaysVisible

这个参数和stateAlwaysVisible的区别是当我们从这个界面跳转到下个界面,从下个界面返回到这个界面是软键盘是消失的,当回到这个界面软键盘依旧可以弹出显示,而stateVisible确不会。

上述6个属性定义的是进入界面,软键盘是否显示的。下面3个属性设置的是软键盘和界面显示内容之间的显示关系。

7. adjustResize,adjustPan

我们将这两个属性放在一起讨论。为了说明这个问题,我们先看如下的布局例子

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="3"android:background="@android:color/holo_red_dark"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="这个是一个测试"android:textSize="30sp" /></FrameLayout><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="4"android:background="@android:color/holo_blue_light"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="这个是一个测试"android:textSize="30sp" /></FrameLayout><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:background="@android:color/white"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center" /></FrameLayout>
</LinearLayout>复制代码

adjustResize

adjustResize

adjustPan

adjustPan

由上面两张图我们可以知道,如果设置adjustResize属性,当键盘显示时,通过对界面主窗口的大小调整(压缩等)来实现留出软键盘的大小空间;如果设置adjustPan属性,当键盘显示时,通过对界面布局的移动来保证输入框可以显示出来。

8. adjustUnspecified

这个属性是根据界面中否有可以滚动的控件来判断界面是采用adjustResize还是adjustPan来显示软键盘。如果有可以滚动的控制,那可以将其理解为adjustResize,通过压缩界面来实现.但是是有一个前提的:可通过滚动在较小区域内看到窗口的所有内容。如果没有可以滚动的控件或者不符合前提条件,则是采用adjustPan,及移动布局来实现。

2. 软键盘的打开和关闭

软键盘的打开和关闭主要通过InputMethodManager实现。InputMethodManager关于打开关闭软键盘的方法主要有如下几个方法。

方法说明
hideSoftInputFromInputMethod(IBinder token, int flags)关闭/隐藏软键盘,让用户看不到软键盘,但是传入的token必须是是系统中token。
hideSoftInputFromWindow(IBinder windowToken, int flags)和下面hideSoftInputFromWindow方法一样,只是resultReceiver传入的值null
hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver)关闭/隐藏软键盘,和第一个方法的区别是他传入的token是系统界面中View窗口的token
showSoftInput(View view, int flags, ResultReceiver resultReceiver)和hideSoftInputFromWindow对应
showSoftInput(View view, int flags)同上面一个方法,但是默认的resultReceiver为null
showSoftInputFromInputMethod(IBinder token, int flags)和hideSoftInputFromInputMethod对应
toggleSoftInput(int showFlags, int hideFlags)该方法是切换软键盘,如果软键盘打开,调用该方法软键盘关闭;反之如果软键盘关闭,那么就打开
toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags)和上面一个方法一样,区别是传入的当前View的token
  1. 在上述方法中我们看到需要传入相关flags,相关flags有如下几个

    参数 | 说明
    -------------------|---
    HIDE_IMPLICIT_ONLY | 表示软键盘只有在用户未明确显示的情况才被隐藏
    HIDE_NOT_ALWAYS | 表示软键盘将一致隐藏,除非调用SHOW_FORCED才会显示
    SHOW_FORCED | 表示软键盘强制显示不会被关闭,除非用户明确的要关闭
    SHOW_IMPLICIT | 表示软键盘接收到一个不明确的显示请求。

  2. 我们经常看到用户传入的参数为0,不属于上述4个,那显示的是什么呢?其实如果传入的hideflag的话表示的是就是关闭软键盘,之前传入的参数不会改变,showflag的话表示的是SHOW_IMPLICIT

总结:

关闭软键盘的方法为

    public void hideKeyboard(View view) {((InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);}复制代码

打开关键盘的方法为

    public void OpenKeyboard(View view) {((InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_NOT_ALWAYS);}复制代码

3. 监听软键盘的打开和关闭

3.1 常规方法

监听软键盘的打开和关闭最常规的方法是监听View的层次结构,这个View的层次结构的发生全局性的事件如布局发生变化等我们可以通过调用getViewTreeObserver监听到布局的变化。代码实例如下:

    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {// 虚拟键的高度int navigationBarHeight = 0;int resourceId = activityRootView.getContext().getResources().getIdentifier("navigation_bar_height", "dimen", "android");//判断是否有虚拟键if (resourceId > 0 && checkDeviceHasNavigationBar(activityRootView.getContext())) {navigationBarHeight = activityRootView.getResources().getDimensionPixelSize(resourceId);}// status bar的高度int statusBarHeight = 0;resourceId = activityRootView.getContext().getResources().getIdentifier("status_bar_height", "dimen", "android");if (resourceId > 0) {statusBarHeight = activityRootView.getResources().getDimensionPixelSize(resourceId);}// 获得app的显示大小信息Rect rect = new Rect();((Activity)activityRootView.getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);//获得软键盘的大小:屏幕高度-(status bar的高度+虚拟键的高度+app的显示高度)int keyboardHeight = ((Activity) activityRootView.getContext()).getWindow().getDecorView().getRootView().getHeight() - (statusBarHeight + navigationBarHeight + rect.height());if (keyboardHeight>100 && !isSoftKeyboardOpened) {isSoftKeyboardOpened = true;notifyOnSoftKeyboardOpened(keyboardHeight);Log.d(TAG, "keyboard has been opened");} else  if(keyboardHeight <100 && isSoftKeyboardOpened){isSoftKeyboardOpened = false;notifyOnSoftKeyboardClosed();Log.d(TAG, "keyboard has been closed");}}} )复制代码

status bar是否存在其实也需要判断,但是因为app本身可以判断当前界面是否显示status的高度,所以上述代码默认status显示。

3.2 重写根布局的onMeasure

该方法使用于windowSoftInputMode被设置为adjustResize。如上文所致,adjustResize是采用压缩界面布局来实现软键盘可以正常显示。具体代码如下

public class KeyBoardFrameLayout extends FrameLayout {public KeyBoardFrameLayout(@NonNull Context context) {super(context);}public KeyBoardFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public KeyBoardFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);final int actualHeight = getHeight();int keyboardHeight = actualHeight - proposedheight;if (keyboardHeight > 100) {notifyOnSoftKeyboardOpened(keyboardHeight);} else if (keyboardHeight < -100) {notifyOnSoftKeyboardClosed();}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}复制代码

对比上述两种方法:

  1. 第一种方法的优点是不管windowSoftInputMode被设置为什么,都可以实现软键盘的开关键盘;第二种需要将上述的布局作为界面的根布局才能实现监听
  2. 第一种方法的缺点是事后监听,已当onLayout之后才会拿到监听,这个导致界面容易出现闪屏的情况;而第二种方法是在界面onLayout之前就拿到了监听,因此不会出现闪屏的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393973.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git php框架,如何用Git安装TP框架

本篇文章主要给大家介绍如何用Git安装Thinkphp框架。关于TP框架的安装&#xff0c;想必大家都知道较为常见的方式是通过composer安装tp框架。首先简单的给大家介绍下Git和TP框架。Git是一个开源的分布式版本控制系统&#xff0c;可以快速&#xff0c;高效地处理从小型到大型项目…

C#EF中,使用类似于SQL中的% 模糊查询

最近在做项目的时候需要使用到模糊查询,但是后台使用EF写的 而不是ADO或者是Dapper,如果是这样的话,我们就可以使用Sql语句直接进行模糊查询 现在我们需要在LINQ中使用类似于模糊查询 在EF中有两个方法:StartsWith()和EndWith() StartsWith(): 在转到定义时 我们可以看见,这个方…

android toast居中显示_Android Toast 设置到屏幕中间,自定义Toast的实现方法,及其说明...

Android Toast用于在手机屏幕上向用户显示一条信息&#xff0c;一段时间后信息会自动消失。信息可以是简单的文本&#xff0c;也可以是复杂的图片及其他内容(显示一个view)。1.简单用法Toast.makeText(midlet.getApplicationContext(), "用户名不能为空", Toast.LENG…

leetcode103. 二叉树的锯齿形层次遍历(bfs)

给定一个二叉树&#xff0c;返回其节点值的锯齿形层次遍历。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xff09;。例如&#xff1a; 给定二叉树 [3,9,20,null,null,15,7],3/ \9 20/ \15 7 返回…

LintCode Find the Weak Connected Component in the Directed Graph

原题链接在这里&#xff1a;http://www.lintcode.com/en/problem/find-the-weak-connected-component-in-the-directed-graph/ 题目&#xff1a; Find the number Weak Connected Component in the directed graph. Each node in the graph contains a label and a list of its…

简单了解tengine

Tengine是由淘宝网发起的Web服务器项目。它在Nginx的基础上&#xff0c;针对大访问量网站的需求&#xff0c;添加了很多高级功能和特性。最终目标是打造一个高效、稳定、安全、易用的Web平台。1、基本的HTTP服务器特性1.处理静态文件&#xff0c;索引文件以及自动索引&#xff…

服务器创建多个dhcp服务_如何在15分钟内创建无服务器服务

服务器创建多个dhcp服务by Charlee Li通过李李 如何在15分钟内创建无服务器服务 (How to create a serverless service in 15 minutes) The word “serverless” has been popular for quite a while. When Amazon released the AWS Lambda service in 2015, many tools emerg…

php snoopy视频教程,php的Snoopy类

用了两天这个类&#xff0c;发现很好用。获取请求网页里面的所有链接&#xff0c;直接使用fetchlinks就可以&#xff0c;获取所有文本信息使用fetchtext(其内部还是使用正则表达式在进行处理)&#xff0c;还有其它较多的功能&#xff0c;如模拟提交表单等。使用方法&#xff1a…

网页解析 css

网页解析 css转载于:https://www.cnblogs.com/guozepingboke/p/10792298.html

如何看pg数据库版本号_查看pg数据库版本

PostgreSQL 基本命令链接&#xff1a;http://blog.itpub.net/28602568/viewspace-1841163/标题&#xff1a;PostgreSQL 基本命令作者&#xff1a;&#xff4c;ōττ&#xff52;&#xff59;©版权所有[文章允许转载,但必须以链接方式注明源地址,否则追究法律责任.]安装步…

leetcode1091. 二进制矩阵中的最短路径(bfs)

在一个 N N 的方形网格中&#xff0c;每个单元格有两种状态&#xff1a;空&#xff08;0&#xff09;或者阻塞&#xff08;1&#xff09;。一条从左上角到右下角、长度为 k 的畅通路径&#xff0c;由满足下述条件的单元格 C_1, C_2, ..., C_k 组成&#xff1a;相邻单元格 C_i …

lock和synchronized的同步区别与选择

区别如下&#xff1a; 1. lock是一个接口&#xff0c;而synchronized是java的一个关键字&#xff0c;synchronized是内置的语言实现&#xff1b;&#xff08;具体实现上的区别在《Java虚拟机》中有讲解底层的CAS不同&#xff0c;以前有读过现在又遗忘了。&#xff09; 2. syn…

首页显示登陆用户名php,首页登录后怎么在首页显示用户名以及隐藏登录框?

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼index.php&#xff1a;登录页面用户名&#xff1a;密码&#xff1a;没有账号&#xff1f;立即注册——————————————————————————doaction.php&#xff1a;header("Content-type:text/html;charsetutf…

react中使用构建缓存_通过在React中构建Tic Tac Toe来学习ReasonML

react中使用构建缓存3. 7. 2018: UPDATED to ReasonReact v0.4.23. 7. 2018&#xff1a;更新为ReasonReact v0.4.2 You may have heard of Reason before. It’s a syntax on top of OCaml that compiles to both readable JavaScript code and to native and bytecode as well…

echart vue 图表大小_vue里echarts自适应窗口大小改变

echarts的图表提供了一个resize方法可以自适应屏幕窗口改变&#xff0c;而重新渲染图表大小的功能。因此我们只要监听浏览器的窗口改变的resize事件&#xff0c;再结合echarts的图表&#xff0c;就可以实现我们想要的功能了。如果是单个图表的情况的话用window.onresize myCha…

用js检测文本框中输入的是否符合条件并有错误和正确提醒

<!DOCTYPE html> <html><head><meta charset"utf-8"><title>捕获异常</title></head><script type"text/javascript">function my_func(){try{xdocument.getElementById("input_id").value;ale…

leetcode784. 字母大小写全排列(回溯)

给定一个字符串S&#xff0c;通过将字符串S中的每个字母转变大小写&#xff0c;我们可以获得一个新的字符串。返回所有可能得到的字符串集合。 示例: 输入: S “a1b2” 输出: [“a1b2”, “a1B2”, “A1b2”, “A1B2”] 输入: S “3z4” 输出: [“3z4”, “3Z4”] 输入: S…

Petapoco使用SQLite的异常问题

在DbProviderFactory 初始化时&#xff0c;报一个"System.Data.SQLite.SQLiteFactory”的类型初始值设定项引发异常。 解决&#xff1a;不光要引用System.Data.SQLite。还要把SQLite.Interop.dll添加到运行目录下。转载于:https://www.cnblogs.com/crazy29/p/7595552.html…

CPP函数调用的方法

相比于C语言中函数可以直接调用&#xff0c;CPP的函数由于命名存在隐式添加&#xff0c;因此需要通过一套流程才能调用&#xff1a; 1. 编码中&#xff0c;使用extern "C" 定义一个C函数&#xff0c;返回获取对象的指针&#xff1b;执行该函数时&#xff0c;获得一个…

php 算法 二进制文件,关于PHP二进制流 逐bit的低位在前算法(详解)_PHP教程

复制代码 代码如下:/******************************************************* 逐bit的低位在前算法* param $x* return int*/function reverse($x){$result 0;for($i 0; $i < 8; $i){$result ($result <> $i));}return $result & 0xff;}调用展示&#xff1a;…