内容简介:最近改 bug 的时候碰到一个小知识点,在搜索界面希望键盘上的 enter 键改为搜索按钮。也就是下图的效果,是不是非常常见。然后我就记得 Editext 有个 imeOptions 的属性,可以设置 enter 键的效果。所以果断在 xml 中写下如果设置了 imeOptions 属性,键盘没有变化 ,那么需要单独加一些其他的属性配合使用,xml中 属性设置:
最近改 bug 的时候碰到一个小知识点,在搜索界面希望键盘上的 enter 键改为搜索按钮。也就是下图的效果,是不是非常常见。
然后我就记得 Editext 有个 imeOptions 的属性,可以设置 enter 键的效果。所以果断在 xml 中写下 android:imeOptions="actionSearch"
,然后把问题改为已修复,信心满满。结果等编译运行起来在手机上发现没有起作用,还是 enter 键。 搜索了一下,发现大家都是这样回答的:
如果设置了 imeOptions 属性,键盘没有变化 ,那么需要单独加一些其他的属性配合使用,xml中 属性设置:
1 将singleLine设置为true
2.或者将inputType设置为text
试了一下,果然 ok 了。但为什么这样设置显示就对了呢?你是不是同样也有疑问? 所以就让我们共同去探寻答案吧!
ImeOptions 属性源码解析
这里首先推荐一个看源码的插件: AndroidSourceView 。
Step1
因为如果是在 JAVA 文件中,我们设置 imeOptions 属性代码为: editText.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
所以首先要定位到 setImeOptions()
这个方法 ,在 EdiText 中没有搜到,所以果断跳到 EditText 的父类 TextView 的源码中,然后发现目标:
/** * Change the editor type integer associated with the text view, which * is reported to an Input Method Editor (IME) with {@link EditorInfo#imeOptions} * when it has focus. * @see #getImeOptions * @see android.view.inputmethod.EditorInfo * @attr ref android.R.styleable#TextView_imeOptions * 当输入法编译器(IME)获取焦点的时候,通过{@link EditorInfo#imeOptions} 报告给输入法编辑器, * 来更改与文本视图关联的编辑器类型值。 */ public void setImeOptions(int imeOptions) { //1.判断是否需要创建 Editor 对象 createEditorIfNeeded(); //2.判断是否需要创建 InputContentType mEditor.createInputContentTypeIfNeeded(); //3. 将入参赋值给InputContentType.imeOptions mEditor.mInputContentType.imeOptions = imeOptions; } 复制代码
这个方法里面只是进行了判断是否需要创建一些对象,然后将我们的入参赋值给 InputContentType.imeOptions。从这方法的注释中我们可以知道关键对象是 EditorInfo#imeOptions
。
Step2
继续搜索关键字 imeOptions ,然后发现下面这个方法:
@Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { if (onCheckIsTextEditor() && isEnabled()) { mEditor.createInputMethodStateIfNeeded(); outAttrs.inputType = getInputType(); if (mEditor.mInputContentType != null) { outAttrs.imeOptions = mEditor.mInputContentType.imeOptions; outAttrs.privateImeOptions = mEditor.mInputContentType.privateImeOptions; outAttrs.actionLabel = mEditor.mInputContentType.imeActionLabel; outAttrs.actionId = mEditor.mInputContentType.imeActionId; outAttrs.extras = mEditor.mInputContentType.extras; outAttrs.hintLocales = mEditor.mInputContentType.imeHintLocales; } else { outAttrs.imeOptions = EditorInfo.IME_NULL; outAttrs.hintLocales = null; } if (focusSearch(FOCUS_DOWN) != null) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT; } if (focusSearch(FOCUS_UP) != null) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS; } if ((outAttrs.imeOptions & EditorInfo.IME_MASK_ACTION) == EditorInfo.IME_ACTION_UNSPECIFIED) { if ((outAttrs.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0) { // An action has not been set, but the enter key will move to // the next focus, so set the action to that. outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT; } else { // An action has not been set, and there is no focus to move // to, so let's just supply a "done" action. outAttrs.imeOptions |= EditorInfo.IME_ACTION_DONE; } if (!shouldAdvanceFocusOnEnter()) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION; } } if (isMultilineInputType(outAttrs.inputType)) { // Multi-line text editors should always show an enter key. outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION; } outAttrs.hintText = mHint; if (mText instanceof Editable) { InputConnection ic = new EditableInputConnection(this); outAttrs.initialSelStart = getSelectionStart(); outAttrs.initialSelEnd = getSelectionEnd(); outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType()); return ic; } } return null; } 复制代码
然后我们只关心我们探究的信息,所以 伪代码 如下:
public InputConnection onCreateInputConnection(EditorInfo outAttrs) { // return mEditor == null ? EditorInfo.TYPE_NULL : mEditor.mInputType outAttrs.inputType = getInputType(); if (mEditor.mInputContentType != null) { outAttrs.imeOptions = mEditor.mInputContentType.imeOptions; } else { outAttrs.imeOptions = EditorInfo.IME_NULL; } if (focusSearch(FOCUS_DOWN) != null) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT; } if (focusSearch(FOCUS_UP) != null) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS; } if ((outAttrs.imeOptions & EditorInfo.IME_MASK_ACTION) == EditorInfo.IME_ACTION_UNSPECIFIED) { //..代码省略 } if (isMultilineInputType(outAttrs.inputType)) { // Multi-line text editors should always show an enter key. //多行文本编译器总是会显示 enter 键 outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION; } return null; } 复制代码
Step3
我们首先分析一下:
- 第一个 if 判断:
mEditor.mInputContentType
这个值是否为空,答案是 false ,因为我们在setImeOptions
方法的第 3 步已经给它赋值了,所以不会为空,所以outAttrs.imeOptions
结果为我们设置的值 - 第二个 if 判断:是来寻找我们的 Editext 对象的往下的一个方向是否存在可以获取焦点的 View,这个得看实际输入框下面布局是否还会有一个输入框,目前项目没有,所以 false
- 第三个 if 判断:跟第二个条件一样,只过是方向为向上查找
- 第四个 if 判断:首先
(outAttrs.imeOptions & EditorInfo.IME_MASK_ACTION
值是多少呢,我们代码里设置的值是IME_ACTION_SEARCH
,值为 3,EditorInfo.IME_MASK_ACTION
的值为 255 ,取二进制值为 00000011 & 1111 1111 = 00000011 十进制为 3,而EditorInfo.IME_ACTION_UNSPECIFIED
值为 0,所以结果为 false。
到目前为止 outAttrs.imeOptions
的结果依然为我们在代码中设置的值。
Step4
来看最后一个 if 判断: isMultilineInputType(outAttrs.inputType)
光看字段意思我们能猜到判断输入框是不是多行输入。看一下具体代码:
private static boolean isMultilineInputType(int type) { return (type & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); } 复制代码
type 这个值为我们在 onCreateInputConnection() 方法中通过getInputType () 方法获取,结果为返回我们代码中设置的 inputType 值,而我们代码中没有设置,那么这个 inputType 的默认值是什么呢?源码中没有找到,然后我自己 debug 了一下,结果如下图:
所以默认值为 131073,而 InputType 各种类型的值如下:
public interface InputType { int TYPE_CLASS_DATETIME = 4; int TYPE_CLASS_NUMBER = 2; int TYPE_CLASS_PHONE = 3; int TYPE_CLASS_TEXT = 1; int TYPE_DATETIME_VARIATION_DATE = 16; int TYPE_DATETIME_VARIATION_NORMAL = 0; int TYPE_DATETIME_VARIATION_TIME = 32; int TYPE_MASK_CLASS = 15; int TYPE_MASK_FLAGS = 16773120; int TYPE_MASK_VARIATION = 4080; int TYPE_NULL = 0; int TYPE_NUMBER_FLAG_DECIMAL = 8192; int TYPE_NUMBER_FLAG_SIGNED = 4096; int TYPE_NUMBER_VARIATION_NORMAL = 0; int TYPE_NUMBER_VARIATION_PASSWORD = 16; int TYPE_TEXT_FLAG_AUTO_COMPLETE = 65536; int TYPE_TEXT_FLAG_AUTO_CORRECT = 32768; int TYPE_TEXT_FLAG_CAP_CHARACTERS = 4096; int TYPE_TEXT_FLAG_CAP_SENTENCES = 16384; int TYPE_TEXT_FLAG_CAP_WORDS = 8192; int TYPE_TEXT_FLAG_IME_MULTI_LINE = 262144; int TYPE_TEXT_FLAG_MULTI_LINE = 131072; int TYPE_TEXT_FLAG_NO_SUGGESTIONS = 524288; int TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 32; int TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 48; int TYPE_TEXT_VARIATION_FILTER = 176; int TYPE_TEXT_VARIATION_LONG_MESSAGE = 80; int TYPE_TEXT_VARIATION_NORMAL = 0; int TYPE_TEXT_VARIATION_PASSWORD = 128; int TYPE_TEXT_VARIATION_PERSON_NAME = 96; int TYPE_TEXT_VARIATION_PHONETIC = 192; int TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 112; int TYPE_TEXT_VARIATION_SHORT_MESSAGE = 64; int TYPE_TEXT_VARIATION_URI = 16; int TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 144; int TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 160; int TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 208; int TYPE_TEXT_VARIATION_WEB_PASSWORD = 224; } 复制代码
结合 stackoverflow 上 Default inputType of EditText in android 答案和 InputType 的值,也就是说 inputType 默认值 为 InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_MULTI_LINE
组合的结果。
然后我们继续往下看,isMultilineInputType() 方法的返回值
(type & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE 复制代码
转换为十进制为: (131073 & (15 | 131072)) == 1 | 131072
转换为二进制为: (100000000000000001 &(1111 | 100000000000000000)) == 1 | 100000000000000000
即 100000000000000001 == 100000000000000001
即 true。
所以会进入最后一个条件中,而该返回值明确指出 多行文本编译器总是会显示 enter 键 。所以我们会看到我们设置的属性 失效 了。
而如果我们设置了 singleLine = true
,源码中是这样设置的:
/** * Adds or remove the EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE on the mInputType. * @param singleLine */ private void setInputTypeSingleLine(boolean singleLine) { if (mEditor != null && (mEditor.mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) { if (singleLine) { mEditor.mInputType &= ~EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; } else { mEditor.mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; } } } 复制代码
如果 singleLine 为 true,inputType = ~ 131072,即011111111111111111 ,最后计算结果为 111111111111111111 == 100000000000000001
,显然 false。
或者设置了inputType = TYPE_CLASS_TEXT 我们也可以得出返回值为 false,所以不会进判断条件,也就是 imeOptions 的值就是我们在代码里或者 xml 中设置的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 行间距失效问题
- 前端实现设置缓存数据定时失效
- 5分钟探究Spring事务失效原因
- Andorid内Aspectj切面失效分析
- Xcode 代码提示失效以及引发的感想
- Firefox 已发布“插件失效”证书修复补丁
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
构建之法(第三版)
邹欣 / 人民邮电出版社 / 2017-6 / 69.00元
软件工程牵涉的范围很广, 同时也是一般院校的同学反映比较空洞乏味的课程。 但是,软件工程 的技术对于投身 IT 产业的学生来说是非常重要的。作者有在世界一流软件企业 20 年的一线软件开 发经验,他在数所高校进行了多年的软件工程教学实践,总结出了在 16 周的时间内让同学们通过 “做 中学 (Learning By Doing)” 掌握实用的软件工程技术的教学计划,并得到高校师生的积极反馈。在此 ......一起来看看 《构建之法(第三版)》 这本书的介绍吧!