博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Android】设置EditText为仅输入数字且最多只能有两位数字
阅读量:6216 次
发布时间:2019-06-21

本文共 3917 字,大约阅读时间需要 13 分钟。

需求很简单,就是要设置一个EditText仅能输入数字且输入的数字中小数部分最多可以有两位。

第一步,很简单,在XML文件中,将EditText的inputType设置成NumberDecimal,多余的属性我就不写出来,只写出主要的部分:

第二部,代码中修改EditText 的addTextChangedListener 方法,同样的先上代码,再来解释:

EditText.addTextChangedListener(new TextWatcher() {	        //    Tips: 		//    1. onTextChanged和beforTextChanged传入的参数s其实是当前EditText的文字内容,而不是当前输入的内容		//    2. 如果在任意一个方法中调用了设置当前EditText文本的方法,setText(),实际都触发了一遍这3个函数,		//       所以要有判断条件,在if体内去setText,而且就需要手动设置光标的位置,不然每次光标都会到最开始的位置		//    3. onTextChanged中,before=0: 增加;before=1: 点击删除按键					private int count_decimal_points_ = 0;  // 标识当前是不是已经有小数点了		private int selection_start_;  			// 监听光标的位置		private StringBuffer str_buf_;			// 缓存当前的string,用以修改内容		@Override		public void onTextChanged(CharSequence s, int start, int before,				int count) {			str_buf_ = new StringBuffer(s.toString().trim());			// 先判断输入的第一位不能是小数点			if (before == 0 && s.length() == 1 && s.charAt(start) == '.') {				recharge_money.setText("");			} else if (before == 0 && count_decimal_points_ == 1) {			// 在判断如果当前是增加,并且已经有小数点了,就要判断输入是否合法;如果是减少不做任何判断				// 注意在if语句中都是在else体内调用了设置光标监听位的方法,因为在调用setText之后会出现嵌套的情况				// 非合法的输入包括: 1. 输入的依旧是小数点,2.小数点后位数已经达到两位了				if (s.charAt(start) == '.' ||  (start - str_buf_.indexOf(".") > 2) ) {					str_buf_.deleteCharAt(start);					recharge_money.setText(str_buf_);				} else {					selection_start_ = str_buf_.length();		// 设置光标的位置为结尾				}			} else {				selection_start_ = str_buf_.length();		// 设置光标的位置为结尾				}		}		@Override		public void beforeTextChanged(CharSequence s, int start, int count,				int after) {			if (s.toString().contains(".")) {				count_decimal_points_ = 1;			} else {				count_decimal_points_ = 0;	// 因为可能存在如果是删除的话,把小数点删除的情况			}		}		@Override		public void afterTextChanged(Editable s) {			// 重置光标位置			recharge_money.setSelection(selection_start_);						if (s != null) {				try {					// TODO Your things				} catch (NumberFormatException e) {					e.printStackTrace();				}			}		}		});
 
其实我们看到在listener中是new 了一个TextWatcher类,在TextWatcher类中,其实有3个方法,beforeTextChanged、onTextChanged和afterTextChanged。 从它们的名字中我们也不难看出分别是当text发生变化的时候,要做的处理。

在类中,我们声明了3个变量,变量的作用我在注释里面也添加了,这里就不啰嗦了。注意的是之所以用StringBuffer来代替String是因为StringBuffer的效率更高,至于为什么,自行Google。

看了一下我的代码,觉得我该说的东西在注释里面都已经写出来了。这里需要特别注意的是,如果在你的类中,你调用了EditText的setText方法,那么就会立即触发TextWatch类,所以,如果你不加if条件判断,而是直接setText,那么就会出现死循环最终内存泄露而崩溃。所以一定要注意,比如你发现用户的输入不合法,要把刚输入的内容删除掉,重新set一下当前EditText的内容,那么一定是在if循环语句中setText。

还有一点也是和这个相关的,就是我开始的时候,在onTextChanged方法中,把设置光标位置的语句放在了if循环体之外,因为我觉得每次不管你是不是满足条件,都要执行一遍重置光标的操作,就出现了bug,后来是打log的时候才发现了,这里我把代码中的log内容省去了。

具体情况我来给大家解释一遍,我们先来看一下我最初的代码:

public void onTextChanged(CharSequence s, int start, int before,					int count) {				str_buf_ = new StringBuffer(s.toString().trim());				// 先判断输入的第一位不能是小数点				if (before == 0 && s.length() == 1 && s.charAt(start) == '.') {					LogUtil.logMsg("输入错误","第一位不能是小数点");					recharge_money.setText("");				} else if (before == 0 && count_decimal_points_ == 1) {					// 在判断如果当前是增加,并且已经有小数点了,就要判断输入是否合法;如果是减少不做任何判断					// 注意在if语句中都是在else体内调用了设置光标监听位的方法,因为在调用setText之后会出现嵌套的情况					// 非合法的输入包括: 1. 输入的依旧是小数点,2.小数点后位数已经达到两位了					if (s.charAt(start) == '.' ||  (start - str_buf_.indexOf(".") > 2) ) {						str_buf_.deleteCharAt(start);						EditText.setText(str_buf_);					}				}selection_start_ = str_buf_.length();		// 设置光标的位置为结尾				}
 
 
重点就在最后一行,我在任何时候都会设置光标的位置。我们来看bug是如何产生的:

加入这时候已经有一串合法的数字123.45写在了EditText中,这个时候光标的位置是6,假设这个时候我们又输入了一个数字6,那么在TextWatch类中,selection_start_实际上变成了7,因为在这个方法中,CharSequence s,也就是str_buf_的长度是7,也就是123.456,然后我们发现已经有了两位小数了,手动设置EditText的setText方法,把它改成了123.45,前面我们说过了,这里会有一个嵌套调用,相当于递归了一下,注意我们的程序在afterTextChanged中要重置光标位置的,bug就出在这里。

我们来画一下流程吧:

123.456 onTextChanged --> 123.45 onTextChanged --> 123.45 afterTextChanged --> 123.456 afterTextChanged

我省去了beforeTextChanged的过程,但是可以看到,我们在循环体的外面是要调用123.456的afterTextChanged方法的,这个方法里面的selection_start_也就是光标位置是7,但是其实,这个时候text的内容已经变成了123.45,那这个text只有6位,你要把光标设置在7,那一定会崩溃的。

所以,因为有嵌套的关系,我们一定要谨慎地处理每一步。

转载地址:http://idvja.baihongyu.com/

你可能感兴趣的文章
倒计时特效的CountAnimationLabel
查看>>
iOS开发UI篇—使用picker View控件完成一个简单的选餐应用
查看>>
Code Jam练习
查看>>
tcmalloc浅析
查看>>
(一一三)第九章复习题
查看>>
拍立淘---试妆魔镜 OpenGL ES 2.0 框架及性能优化
查看>>
PostgreSQL HOT STANDBY using log shipping
查看>>
Autowired与Resource的区别
查看>>
send-mail: fatal: parameter inet_interfaces: no local interface found for ::1
查看>>
Shell基础之-cut命令
查看>>
node.js学习笔记(26) node-orm进阶一
查看>>
微信公众号网页开发——实用真机调试
查看>>
【译】函数组件和类组件有什么不同?
查看>>
Anka——渐进式小程序开发工具集
查看>>
《你不知道的Javascript--上卷 学习总结》(作用域)
查看>>
有赞996刷屏:男程序员们,别再低头写代码了
查看>>
008.前端面试排雷之唱、跳、rap三步曲( 二 )跳篇
查看>>
Docker安装
查看>>
es6新增数组方法简便了哪些操作?
查看>>
art-template:input框中传入视频后不能进行输入/删除操作
查看>>