前言:在最近一个项目的登录页上,输入手机号码这个输入框,UI稿要求显示344样式的格式化手机号码,例如“130 1234 5678”,在之前其实也有过类似的需求,但是在实现344格式化手机号码的过程中或多或少碰到不少坑,当时也没有深究,以项目排期紧为由将需求拍回去了,折中的方案是设置输入框的android:inputType=“phone”,android:maxLength=“11”,这是最常见的手机号输入框的实现方式,全部由系统自己处理,无bug,程序员的最爱,但是这一次我决定say no!

一、调研主流App

之前想做这样的一个格式化手机号输入框时也查看过网上的一些代码,但是在使用他们的代码时,总会有各种各样的bug(空指针、角标越界等等),各种各样的技术博客都是将别人的代码拷过来不假思索的粘贴就变成自己的了,也不实践完善验证代码的正确性,所以目前没看到一款真正能用,不会出现bug的输入框控件。

准备干之前我想各一线大厂这种格式化手机号码的输入框肯定是正确好用的(崇拜的心理),于是准备看看他们实现的效果都是啥样的,结果也是让我感到惊讶,一起来看看!

为保证调研质量,所有app都升级到了最新版本。

1.今日头条 V7.2.9

今日头条的使用情况:
手机号登录为344格式化样式,最多只能输入11位有效字符,但是还可以输入字符,没有做输入过滤,在中间删除字符重新输入过程中无崩溃。

2.新浪微博 V9.6.2

新浪微博的使用情况:
在输入过程中,微博过滤所有的无效字符,只能输入0-9这些数字,其他的都不会输入。但是却没有做手机号位数限制,好吧,如果说与国家的手机号有关,那我无话可说,但是从第11位数字往后就没有了格式化了,也就是上图所示这样。

3.美团 V10.0.401

美团的使用情况:
美团在输入时,有最多11位数字限制,如果将光标移动到非末尾位置输入,会自动将最后一位移除,在光标位置插入新的字符,但是也没有做过滤,如图所示可以输入标点符号,字母只能输入p。

4.网易云音乐 V6.2.2

网易云音乐的使用情况:
网易云音乐并没有做344格式化手机号的处理,默认最多输入11位字符,输入满11位时,光标在非末尾位置时无法增加新的字符,如图所示,网易云可以输入加减乘除、逗号、点、字母w和p。

5.支付宝 V10.1.65.6567

支付宝的使用情况:
也没做位数限制,从第11位开始没有格式化样式了,过滤掉了其他的字符,但是还能输入减号。

6.优酷 V8.0.3

优酷的使用情况:
大优酷竟然不让截屏?可以看到没有做344手机号格式化,也没有限制输入长度,倒是过滤掉了所有的非数字的字符。

7.安居客 V12.16.4

安居客的使用情况
最多输入11位数字,也做了344格式化手机号码,所有字符无法输入(过滤的很干净),但是当我想点中间的某位数字时,竟然整块选中无法取消,这个时候你只有两种选择,要不点击获取验证码,要不重新输入手机号码,这个功能真的非常恶心!

8.贝壳找房 V2.11.0

贝壳找房的使用情况
在贝壳中进行手机号输入,问题和网易云音乐一样,可以输入±*/,.wp这些字符,并且还有一点也比较恶心,当光标移动到非末尾位置时,这时候不论是删除或者输入字符时,光标马上会跳到最后一位,个人感觉这个用户体验非常不好。

二、功能实现

通过对上述一些生活中常用的覆盖衣食住行的主流app的输入框比较,现在没有一款能够满足真正意义上的344格式化手机号码输入框,有的是没有过滤特殊字符,有的是没有做长度限制,这里抛开国际化手机号码长度的问题,以中国现有11位手机号码长度为例,来动手写一个自定义的输入框,真正好用的344格式化号码,这里贴上最终的代码:

/** 实现自定义手机号输入框,手机号码效果为344效果,例如111 1111 1111*/
public class PhoneEditText extends EditText implements TextWatcher {// 特殊下标位置private static final int PHONE_INDEX_3 = 3;private static final int PHONE_INDEX_4 = 4;private static final int PHONE_INDEX_8 = 8;private static final int PHONE_INDEX_9 = 9;private String preCharSequence;private OnPhoneEditTextChangeListener onPhoneEditTextChangeListener;public PhoneEditText(Context context) {super(context);initView();}public PhoneEditText(Context context, AttributeSet attrs) {super(context, attrs);initView();}public PhoneEditText(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView();}public interface OnPhoneEditTextChangeListener {/*** 对外提供接口监听* @param s 字符串* @param isEleven 现在是否是11位数字*/void onTextChange(String s, boolean isEleven);}public void setOnPhoneEditTextChangeListener(OnPhoneEditTextChangeListener listener) {this.onPhoneEditTextChangeListener = listener;}private void initView() {//设置输入过滤器setFilters(new InputFilter[] {new InputFilter() {@Overridepublic CharSequence filter(CharSequence source, int start, int end,Spanned spanned, int dstart, int dend) {//在onTextChanged方法里执行setText(sb.toString());会到这里,内容一样直接返回if (TextUtils.equals(source, preCharSequence)) {return null;}//过滤掉空格和换行,dstart为13表示光标位置是11位数字+2个空格时,返回空字符if (" ".equals(source.toString())|| source.toString().contentEquals("\n")|| dstart == 13) {return "";}//这里是当光标移动到非末尾位置进行输入操作时,返回空字符else if (getPhoneText().toString().length() == 11) {return "";} else {return null;}}}, new InputFilter() {@Overridepublic CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart,int dend) {//过滤掉所有的特殊字符,这里的字母只过滤掉了wp,因为在众多机型测试时,只能输入这两个,如果不放心可以添加a-z所有字母String speChat = "[`~!@#$%^&*()+\\-=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?wp]";Pattern pattern = Pattern.compile(speChat);Matcher matcher = pattern.matcher(source.toString());if (matcher.find()) {return "";} else {return null;}}}});}@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {super.onTextChanged(s, start, before, count);if (TextUtils.equals(preCharSequence, s)) {return;}if (null != onPhoneEditTextChangeListener) {onPhoneEditTextChangeListener.onTextChange(getPhoneText(),getPhoneText().length() == 11);}if (s == null || s.length() == 0) {return;}StringBuilder sb = new StringBuilder();for (int i = 0; i < s.length(); i++) {if (i != PHONE_INDEX_3 && i != PHONE_INDEX_8 && s.charAt(i) == ' ') {continue;} else {sb.append(s.charAt(i));if ((sb.length() == PHONE_INDEX_4 || sb.length() == PHONE_INDEX_9)&& sb.charAt(sb.length() - 1) != ' ') {sb.insert(sb.length() - 1, ' ');}}}//这里主要处理添加空格后的字符串,before=0为输入字符,before=1为删除字符,将光标移动到正确的位置if (!sb.toString().equals(s.toString())) {int index = start + 1;if (sb.charAt(start) == ' ') {if (before == 0) {index++;} else {index--;}} else {if (before == 1) {index--;}}preCharSequence = sb.toString();setText(sb.toString());//对setSelection添加异常捕获,防止出现意外的IndexOutOfBoundsException异常try {setSelection(index);} catch (Exception e) {e.printStackTrace();}}}@Overridepublic void afterTextChanged(Editable s) {}// 获得不包含空格的手机号public String getPhoneText() {String str = getText().toString();return replaceBlank(str);}private String replaceBlank(String str) {String dest = "";if (str != null) {Pattern p = Pattern.compile("\\s*|\t|\r|\n");Matcher m = p.matcher(str);if (m.find()) {dest = m.replaceAll("");}}return dest;}
}

使用也非常简单,在xml文件中使用:

<com.xxxx.widget.PhoneEditTextandroid:id="@+id/et_phone"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/login_editor_bg"android:inputType="phone"android:maxLength="13"android:maxLines="1"android:paddingLeft="16.5dp"android:textColor="@color/white"android:textCursorDrawable="@drawable/cursor_edit"android:textSize="16dp"tools:text="156 1234 5678" />

在activity中使用:

etPhone.setOnPhoneEditTextChangeListener(new PhoneEditText.OnPhoneEditTextChangeListener() {@Overridepublic void onTextChange(String s, boolean isEleven) {setIvClearVisibility(s);if (isEleven && tvSmscode.isEnabled()) {tvSmscode.setTextColor(getResources().getColor(R.color.white));tvSmscode.setClickable(true);} else {tvSmscode.setTextColor(getResources().getColor(R.color.color_30FFFFFF));tvSmscode.setClickable(false);}}});

具体的逻辑都已经在PhoneEditText中内部处理了,外界只用关心回调即可,用起来还是很方便的。

完成后一起来看看最终效果:

效果符合预期,最多输入11位有效数字,过滤所有的非数字字符,光标在中间删除插入也不会出现光标跳闪现象,用户体验好~

三、写在最后

其实这东西并不难,也没有什么技巧,我也只是将现有的各种问题总结处理了一下,作为一个独立的控件能够很方便的被各方使用,以后再碰到类似的需求丝毫不用慌,拿过来用就完了,一次封装,无限使用,给用户提供最完美的用户体验!

如果有问题,欢迎留言,一起探讨~

Android实现真正的344格式化手机号码输入框相关推荐

  1. android格式化时间中文版,Android 仿微信聊天时间格式化显示功能

    本文给大家分享android仿微信聊天时间格式化显示功能. 在同一年的显示规则: 如果是当天显示格式为 HH:mm 例:14:45 如果是昨天,显示格式为 昨天 HH:mm 例:昨天 13:12 如果 ...

  2. Android 应用开发(41)---EditText(输入框)详解

    EditText(输入框)详解 1.设置默认提示文本 如下图,相信你对于这种用户登录的界面并不陌生,是吧,我们很多时候都用的这种界面 相比另外这种,下面这种又如何? 还不赖是吧,当然,不会在这里贴布局 ...

  3. 模仿淘宝手机号码输入框

    <!doctype html> <html lang="en"> <head><meta charset="UTF-8" ...

  4. 邮箱-验证码-手机号码输入框测试用例参考

    一:邮箱输入框 1:不输入任何字符 2:输入中文空格 3:输入英文空格 4:字符串中没有@和点 例如:huiyanni163com 5:字符串中有@没有点 例如:huiyanni@163com 6:字 ...

  5. 输入框【普通输入框,邮箱输入框,验证码输入框,手机号码输入框】测试用例

    普通输入框字段校验测试 1. 不输入,空内容 2. 输入1个字符 3. 若输入框有长度限制为N个字符,测试N-1个字符,N个字符,N+1个字符,N+N+...(超长)这几个边界值 4. 还需要测试下通 ...

  6. “邮箱”“验证码”“手机号码”输入框测试用例

    一:邮箱输入框 1:不输入任何字符 2:输入中文空格 3:输入英文空格 4: 字符串中没有@和点  例如:huiyanni163com 5:字符串中有@没有点  例如: huiyanni@163com ...

  7. Android 验证码和密码输入框,能自定义输入框个数和样式(连体,下划线和方形框) 类似微信支付宝的密码输入框等

    MNPasswordEditText 项目地址:maning0303/MNPasswordEditText  简介: Android 验证码和密码输入框,能自定义输入框个数和样式(连体,下划线和方形框 ...

  8. Android EditText 手机号344格式化输入的最佳实现

    PhoneTextWatcher 手机号格式化监听器,支持普通输入/删除,中间输入/删除,在任意位置下黏贴/剪贴多个数字等多种交互场景. 目前支持的手机号格式为 3-4-4 分隔符可以自定义 Prev ...

  9. Android 调用webservice(ksoap-2-Android)手机号码归属地查询

    之前做过一次但是隔了一个月再做就有点忘了,果然好记性不如烂笔头!还是打算记一下. 现在网络上的一些有关这方面的文章都比较久远了虽然方法没错但是之前的网址都变了所以需要进行一些修改. 记录时间2016/ ...

最新文章

  1. 国服被ban咋看_王者荣耀:赵云不会玩?完美详细攻略教学,看完助你轻松上王者...
  2. 哪个版本python适用于windows-何种版本的Python适合您
  3. div溢出显示时用省略号结尾 .
  4. WinSock编程基础
  5. Leetcode--33. 搜索旋转排序数组
  6. 数字图像处理实验四图像频域增强
  7. 请编写一个程序,用于统计字符串中每个字母的出现次数(字母忽略大小写),统计出结果后,请按照{'a':3,'b':2}的格式输出。
  8. Ph.D. Grind 读后感- by Liangjun
  9. SQL SERVER数据库备份时出现“操作系统错误5(拒绝访问)。BACKUP DATABASE 正在异常终止。”错误的解决办法...
  10. c语言编译器C11,如何检测c11支持编译器与cmake
  11. 计算机统计字符数,如何在电脑上统计文字字数及标点个数
  12. “信用租车”来了 芝麻分满650可在飞猪免押租车
  13. Anaconda Prompt :python.exe - 无法找到入口,无法定位程序输入点
  14. Fabric CA的部署与使用
  15. AR--基本原理实现科普
  16. Laravel SQL查询中first、pluck、lists方法的使用
  17. vc++之windows api
  18. Facebook POP 动画框架 进阶指南
  19. 【java】计算员工工资
  20. 谷歌、互联网股票与以太坊

热门文章

  1. zhaowei -列表知识问答(王者农药)
  2. 安搭Share:小康时代新青年
  3. #(二)、股市是混沌还是浑沌?
  4. Ventoy 制作U盘启动盘 使用教程
  5. 当我闲困的时候,我在想些什么
  6. matlab 模拟滤波器设计与实现,转一个讲matlab设计模拟滤波器的文章2(转)
  7. Postman上传文件测试
  8. lattepanda安装linux系统,LattePandaAI-Linux系统环境部署
  9. 各种题材的手游游戏代码素材推荐,不容错过
  10. Window安全策略的制定与实施