3.4 编辑框
本节介绍Android的两种编辑框,分别是文本编辑框EditText与自动完成编辑框AutoCompleteTextView。在介绍EditText控件时,除了基本属性和方法,还另外阐述了常见的4种编辑处理:更换光标、更换边框、自动隐藏输入法和输入回车符自动换行。
3.4.1 文本编辑框EditText
EditText是文本编辑框,用户可在此输入文本等信息。EditText的常用属性说明如下。
●inputType:指定输入的文本类型,代码中对应的方法是setInputType。输入类型的取值说明见表3-3,若同时使用多种文本类型,则可使用竖线“”把多种文本类型拼接起来。
表3-3 输入类型的取值说明
● maxLength:指定文本允许输入的最大长度。该属性无法通过代码设置。
● hint:指定提示文本的内容,代码中对应的方法是setHint。
● textColorHint:指定提示文本的颜色,代码中对应的方法是setHintTextColor。
编辑框除了上述文本与提示文本的基本操作外,实际开发中还常常关注4个方面:更换编辑框的光标、更换编辑框的边框、自动隐藏输入法、输入回车符自动跳转。
1.更换编辑框的光标
EditText与光标处理有关的属性主要有两个,分别是:
● cursorVisible,指定光标是否可见。代码中对应的方法是setCursorVisible。
● textCursorDrawable,指定光标的图像。该属性无法通过代码设置。
如果要隐藏光标,就要把cursorVisible设置为false。如果要变更光标的样式,就要修改textCursorDrawable设置新图像。如图3-13所示,光标被换成自定义的红色竖线光标。
图3-13 给EditText更换图标样式
2.更换编辑框的边框
EditText的边框通过background属性控制,如果要隐藏边框,就要把background设置为@null;如果要修改边框的样式,就要将background设置为其他边框图形。
下面是一个边框定义XML的例子,一旦编辑框获得焦点(例如用户点击了该编辑框),边框就会显示图形shape_edit_focus;否则默认显示shape_edit_normal。
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" android:drawable="@drawable/shape_edit_focus"/> <item android:drawable="@drawable/shape_edit_normal"/> </selector>
上述自定义边框的效果如图3-14所示,未点击时显示灰色的圆角边框,点击后显示蓝色的圆角边框。
图3-14 给EditText更换边框样式
3.自动隐藏输入法
如果页面上有EditText控件,开发者又没做其他处理,那么用户打开该页面时往往会自动弹出输入法。这是因为编辑框会默认获得焦点,即默认模拟用户的点击操作,于是输入法的软键盘就弹出了。要想避免这种情况,就得阻止编辑框默认获得焦点。比较常见的做法是给该页面的根节点设置focusable和focusableInTouchMode属性,通过将这两个属性设置为true可强制让根节点获得焦点,从而避免输入法自动弹出的尴尬。
由于软键盘通常会遮盖“登录”“确认”“下一步”等按钮,造成用户输入完毕得再点一次返回键才能关闭软键盘。大家都希望省事点,比如手机号输入满11位软键盘自动关闭,这样就会极大改善用户体验。一个好用的App就是在这一点一滴中体现出来的。
想让编辑框文本达到指定长度时自动关闭输入法,开发者需要获得两个参数,第一个是该编辑框允许输入的最大长度,第二个是当前已经输入的文本长度。当已输入的文本长度等于最大长度时,即可触发关闭软键盘。自动隐藏输入法可分解为3个功能点,分别是获取编辑框的最大长度、监控当前已输入的文本长度和关闭软键盘。
(1)获取编辑框的最大长度
前面我们了解到maxLength属性可设置最大长度,但是EditText并没有提供获取最大长度的方法,不过我们可以通过反射方式曲线获得最大长度,具体代码如下:
public static int getMaxLength(EditText et) { int length = 0; try { InputFilter[] inputFilters = et.getFilters(); for(InputFilter filter :inputFilters){ Class<? > c = filter.getClass(); if (c.getName().equals("android.text.InputFilter$LengthFilter")) { Field[] f = c.getDeclaredFields(); for(Field field :f){ if (field.getName().equals("mMax")) { field.setAccessible(true); length=(Integer)field.get(filter); } } } } }catch(Exception e){ e.printStackTrace(); } return length; }
(2)监控当前已输入的文本长度
这个监控操作用到一个文本监听器接口TextWatcher,该接口提供了3个监控方法,具体说明如下。
● beforeTextChanged:在文本改变之前触发。
● onTextChanged:在文本改变过程中触发。
● afterTextChanged:在文本改变之后触发。
这里用到的是afterTextChanged方法,开发者需要自己写个监听器实现TextWatcher接口,另外再给EditText对象调用addTextChangedListener方法注册该监听器。下面是一个具体实现该监听器的例子:
private class HideTextWatcher implements TextWatcher { private EditText mView; private int mMaxLength; private CharSequence mStr; public HideTextWatcher(EditText v) { super(); mView = v; mMaxLength = ViewUtil.getMaxLength(v); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mStr = s; } @Override public void afterTextChanged(Editable s) { if (mStr == null || mStr.length() == 0) return; if (mStr.length() == 11 && mMaxLength == 11) { ViewUtil.hideAllInputMethod(EditHideActivity.this); } else if (mStr.length() == 6 && mMaxLength == 6) { ViewUtil.hideOneInputMethod(EditHideActivity.this, mView); } } }
(3)关闭软键盘
输入法通过系统服务INPUT_METHOD_SERVICE管理,所以隐藏输入法也要通过该服务实现。下面是关闭软键盘的两种方式及其代码:
① 调用toggleSoftInput方法:
public static void hideAllInputMethod(Activity act) { InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE); if(imm.isActive()==true){ //软键盘如果已经打开就要关闭 imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); } }
② 调用hideSoftInputFromWindow方法:
public static void hideOneInputMethod(Activity act, View v) { InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); }
完成隐藏输入法的编码后,可在页面上观察效果,如图3-15所示。此时手机号码输入了10位,还没达到11位的最大长度,故而输入法依然显示。手机号再输入一位数字,总长度11位达到最大长度的限制,于是输入法自动隐藏,如图3-16所示。
图3-15 输入10位手机号码
图3-16 输入11位手机号码
4.输入回车符自动跳转
在录入用户信息时(比如输入姓名、密码等),往EditText控件输入回车键,常常不是换行而是让光标直接跳到下一个编辑框。该功能用到了文本监听器接口TextWatcher,主要监听用户是否输入回车符,如果监控到已输入回车符,就自动将焦点移到下一个控件,从而实现回车符自动跳转的要求。
下面是回车符监听器的代码,注意注释部分的文字说明:
private class JumpTextWatcher implements TextWatcher{ private EditText mThisView=null; private View mNextView=null; public JumpTextWatcher(EditText vThis, View vNext){ super(); mThisView=vThis; if(vNext! =null){ mNextView=vNext; } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after){ } @Override public void onTextChanged(CharSequence s, int start, int before, int count){ } @Override public void afterTextChanged(Editable s){ String str=s.toString(); if(str.indexOf("\r")>=0||str.indexOf("\n")>=0){ //发现输入回车符或换行符 mThisView.setText(str.replace("\r", "").replace("\n", "")); //去掉回车符和换行符 if (mNextView ! = null) { mNextView.requestFocus(); //让下一个视图获得焦点,即将光标移到下个视图 if (mNextView instanceof EditText) { EditText et = (EditText)mNextView; //让光标自动移到编辑框内部的文本末尾 //方式一 :直接调用EditText的setSelection方法 et.setSelection(et.getText().length()); //方式二 :调用Selection类的setSelection方法 //Editable edit = et.getText(); //Selection.setSelection(edit, edit.length()); } } } } }
下面演示一下输入回车符自动跳转的效果图,文本输入完毕后还没输入回车符,此时焦点仍然停留在编辑框,如图3-17所示。输入回车符,此时焦点离开编辑框,并自动移动到“登录”按钮(编辑框的光标消失,按钮背景变深),如图3-18所示。
图3-17 未按回车符
图3-18 已按回车符
3.4.2 自动完成编辑框AutoCompleteTextView
自动完成编辑框一般用于搜索文本框,如在电商App的搜索框输入商品文字时,下方会自动弹出提示词列表,方便用户快速选择具体商品。AutoCompleteTextView的实现原理是:EditText结合监听器TextWatcher与下拉列表Spinner,一旦监控到EditText的文本发生变化,就自动弹出适配好的文字下拉列表,选中具体的下拉项向EditText填入相应文字。
AutoCompleteTextView新增的几个属性都与下拉列表有关,详细说明见表3-4。
表3-4 自动完成编辑框的属性和设置方法说明
下面是使用AutoCompleteTextView的代码:
String[] hintArray = {"第一", "第一次", "第一次写代码", "第一次领工资", "第二", "第二个"}; ArrayAdapter<String> adapter = new ArrayAdapter<String>( this, R.layout.item_dropdown, hintArray); AutoCompleteTextView ac_text= (AutoCompleteTextView) findViewById(R.id.ac_text); ac_text.setAdapter(adapter);
自动完成编辑框的具体效果如图3-19所示,下拉列表的内容会自动与编辑框的文本进行匹配。
图3-19 自动完成编辑框的自动匹配下拉列表