Android EditeText常用功能盘点
这篇集合了项目里经常用到的EditText的需求,以前单个问题总结过,现在放在一起以备后患啊,主要包含以下方面:
1. 判断输入字符长度
2. 键盘的显示与隐藏
3. 对输入内容的限制,列举几种常见的
4. 设置光标的位置
5. EditText禁止复制和粘贴:密码输入框一般都不允许复制和粘贴
6. EditText输入框被键盘遮挡
详细内容:
1. 判断输入字符长度:
计算字符,有时EditText要判断输入字符的长度,可能会有区分中英文的需求。
下面的代码可以计算字符的长度,中文则记为两个字符,英文为一个。
/** * 计算内容的字符数,一个汉字=两个字符,一个中文标点=两个字符 * 注意:该函数的不适用于对单个字符进行计算,因为单个字符四舍五入后都是1 * * @param c * @return */ private int calculateLength(CharSequence c) { int len = 0; for (int i = 0; i < c.length(); i++) { int tmp = (int) c.charAt(i); if (tmp > 0 && tmp < 127) { len++; } else { len += 2; } } return len; }
这篇详细介绍了不同的处理方案:Android字数限制的EditText实现方案研究
2. 键盘的显示与隐藏:经常遇到的需求有以下几种
a). 进入带有EditText的页面自动隐藏键盘:比如登录主页
b). 进入带有EditText的页面自动弹出键盘:比如更改昵称等二级页面
c). 带有EditText的页面键盘显示时,点击EditText以外的任何区域隐藏键盘。
具体方法参见这篇总结:Android基础-EditText键盘的显示与隐藏
还有一种方法是在Activity中重写onTouchEvent,接受到点击事件时就隐藏键盘,但是我遇到一种场景不太灵活:EditText中光标在内容末尾,点击文本末尾键盘一直不能弹出,估计是触点被 onTouchEvent抢了去。这种方法也写在这里参考吧:
// 定义键盘管理类 private InputMethodManager inputMethodManager; private void initView() { inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); // 其他操作。。。 } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (this.getCurrentFocus() != null && this.getCurrentFocus().getWindowToken() != null) { inputMethodManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), InputMethodManager .HIDE_NOT_ALWAYS); } } return super.onTouchEvent(event); }
3. 对输入内容的限制,列举几种常见的:
a). 限制长度,按输入字符内容的个数,不区分中英文
方法: android UI-EditText的长度监听慎用TextWatcher
b). 限制格式:
- 用EditText的xml属性实现基本需求:
几个常用属性
android:password="true" //这样的话输入的内容在输入框中就会以*的样式显示,用于密码
android:inputType="number" //指定输入内容只能是数字,常用于手机号和验证码,还有其他类型
android:digits="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" //这样的话输入的内容只能是这里指定的
- 过滤输入法中的表情:Emoji字符检查与替换
- 利用正则表达式做内容检查,这个可以放在Textwatcher中的afterChaged中:比如
// 昵称最多为16个字符 etNickname.setFilters(new InputFilter[]{new InputFilter.LengthFilter(16)}); etNickname.addTextChangedListener(new TextWatcher() { String temp; @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) { temp = etNickname.getEditableText().toString(); if (temp.length() > 0) { if (rexCheckNickName(temp.trim())) { Toast.makeText(SetUserInfoActivity.this, "昵称格式错误", Toast.LENGTH_SHORT).show(); showToast(getString(R.string.nick_name_wrong)); return; } } } }); } /** * 正则表达式验证昵称 * * @param nickName * @return */ boolean rexCheckNickName(String nickName) { // 昵称格式:限16个字符,支持中英文、数字、减号或下划线 String regStr = "^[\\u4e00-\\u9fa5_a-zA-Z0-9-]{1,16}$"; return nickName.matches(regStr); }
在放一个验证密码的正则表达式:
/** * 正则表达式验证密码 * * @param input * @return */ public static boolean rexCheckPassword(String input) { // 6-20 位,字母、数字、字符 //String reg = "^([A-Z]|[a-z]|[0-9]|[`-=[];,./~!@#$%^*()_+}{:?]){6,20}$"; String regStr = "^([A-Z]|[a-z]|[0-9]|[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]){6,20}$"; return input.matches(regStr); }
c). 检查格式,并实时的给出提示和对关联控件的样式更改。常见场景比如输入手机号后发送验证码Button才有效,验证码倒计时过程中输入内容即使变更验证码也不改变样式继续倒计时,等。类似a)的方式,也放到TextWatcher中处理。
4. 设置光标的位置:
有时进入页面时EditText中以后内容并且获得焦点,比如跳转到修改昵称或者收获地址页面,这时候需要将光标放在文本末尾。
// 旧的昵称非空时进入页面时光标跳转到文本最后 if (!Tools.isStrEmpty(mNickNameOld)) { etNickname.setText(mNickNameOld); etNickname.setSelection(etNickname.getText().length()); }
5. EditText禁止复制和粘贴:密码输入框一般都不允许复制和粘贴
可以使用下面的自定义EditText,禁止了长按,禁止了点击输入提示标志时出现的粘贴键的显示。是StackOverFlow上找来的,具体地址丢了,先借用了~
api11及以上可用,不过现在一般的app要求api都要14以上了吧
@SuppressLint("NewApi") public class NoMenuEditText extends EditText { private final Context context; /** * This is a replacement method for the base TextView class' method of the * same name. This method is used in hidden class android.widget.Editor to * determine whether the PASTE/REPLACE popup appears when triggered from the * text insertion handle. Returning false forces this window to never * appear. * * @return false */ boolean canPaste() { return false; } /** * This is a replacement method for the base TextView class' method of the * same name. This method is used in hidden class android.widget.Editor to * determine whether the PASTE/REPLACE popup appears when triggered from the * text insertion handle. Returning false forces this window to never * appear. * * @return false */ @Override public boolean isSuggestionsEnabled() { return false; } public NoMenuEditText(Context context) { super(context); this.context = context; init(); } public NoMenuEditText(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; init(); } public NoMenuEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.context = context; init(); } private void init() { this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor()); this.setLongClickable(false); } /** * Prevents the action bar (top horizontal bar with cut, copy, paste, etc.) * from appearing by intercepting the callback that would cause it to be * created, and returning false. */ private class ActionModeCallbackInterceptor implements ActionMode.Callback { private final String TAG = NoMenuEditText.class.getSimpleName(); public boolean onCreateActionMode(ActionMode mode, Menu menu) { return false; } public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; } public void onDestroyActionMode(ActionMode mode) { } } }
6. EditText输入框被键盘遮挡
现在的设计都尽量避免了这样的情况,之前有个登录页面,用户名和密码输入在屏幕中央,键盘显示的时候屏幕被自动上移,但是会遮挡输入框下部的一小部分,解决方法有两个:
一是用ResizeLayout布局做自己的根布局,监测到键盘变化后将自己的布局上移。
二是给EditText添加background,就像微信的输入框一样,有个格线,这个背景用点9的图片,这样键盘出现将EditText自动顶上去的时候不会挡住格线,当然也不会挡住输入文本了。
以下是一个ResizeLayout的实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class ResizeLayout extends RelativeLayout { private int mMaxParentHeight = 0; private ArrayList<Integer> heightList = new ArrayList<Integer>(); public ResizeLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (mMaxParentHeight == 0) { mMaxParentHeight = h; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int measureHeight = measureHeight(heightMeasureSpec); heightList.add(measureHeight); if (mMaxParentHeight != 0) { int heightMode = MeasureSpec.getMode(heightMeasureSpec); int expandSpec = MeasureSpec.makeMeasureSpec(mMaxParentHeight, heightMode); super.onMeasure(widthMeasureSpec, expandSpec); return; } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (heightList.size() >= 2) { int oldh = heightList.get(0); int newh = heightList.get(heightList.size() - 1); int softHeight = mMaxParentHeight - newh; /** * 弹出软键盘 */ if (oldh == mMaxParentHeight) { if (mListener != null) { mListener.onSoftPop(softHeight); } } /** * 隐藏软键盘 */ else if (newh == mMaxParentHeight) { if (mListener != null) { mListener.onSoftClose(softHeight); } } /** * 调整软键盘高度 */ else { if (mListener != null) { mListener.onSoftChanegHeight(softHeight); } } heightList.clear(); } else { heightList.clear(); } } private int measureHeight(int pHeightMeasureSpec) { int result = 0; int heightMode = MeasureSpec.getMode(pHeightMeasureSpec); int heightSize = MeasureSpec.getSize(pHeightMeasureSpec); switch (heightMode) { case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = heightSize; break; default: break; } return result; } private OnResizeListener mListener; public void setOnResizeListener(OnResizeListener l) { mListener = l; } public interface OnResizeListener { /** 软键盘弹起 */ void onSoftPop(int height); /** 软键盘关闭 */ void onSoftClose(int height); /** 软键盘高度改变 */ void onSoftChanegHeight(int height); } }