Android InputFilter实战:限制EditText小数点后两位输入的3种实现方式
在金融类App的开发中,处理金额输入是一个高频且必须严谨对待的场景。用户输入“123.456”还是“123.45”,看似只是小数点后一位的差别,却可能直接关系到订单金额、转账数额的准确性,甚至引发后续的业务逻辑错误。作为开发者,我们不仅要确保数据格式的合规性,更要兼顾输入过程中的流畅体验,避免因粗暴的限制而打断用户的输入节奏。
面对“限制EditText只能输入到小数点后两位”这个需求,很多Android开发者首先想到的可能是TextWatcher。它确实直观,通过监听文本变化来实时校验和修正。但深入使用后你会发现,TextWatcher在处理一些边界情况,比如粘贴、光标中间插入、连续删除时,逻辑会变得相当复杂,容易产生意料之外的文本跳动或光标错位。这时,InputFilter方案的优势就凸显出来了。它更像一个“守门人”,在文本真正生效前进行拦截和转换,从源头上控制输入内容,逻辑更集中,实现也往往更优雅。
本文将抛开泛泛而谈,直接切入三种具有不同侧重点的InputFilter实现方案。我们会从最基础的正则匹配开始,逐步深入到处理边界条件和优化用户体验,并最终给出一个兼顾功能与体验的“终极”方案。无论你是正在为金融表单头疼的中级开发者,还是希望更深入理解Android输入系统机制的同好,相信都能从中获得实用的代码和清晰的思路。
1. 理解InputFilter:不只是长度限制器
在动手写代码之前,我们必须先吃透InputFilter的工作原理。很多人对它只有一个模糊的印象——“用来限制输入长度的”。这没错,系统自带的LengthFilter就是这么干的。但它的能力远不止于此。InputFilter是一个接口,其核心方法是filter,它赋予我们在文本“落地”前进行审查和修改的终极权力。
1.1 filter方法的六个关键参数
filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)这个方法签名包含了六个参数,理解它们是编写任何自定义InputFilter的基础。让我们用一个动态的视角来看待它们:
source: 用户即将要输入或粘贴的内容。注意,是“即将”,它还没有成为EditText显示内容的一部分。start&end: 定义了source中有效部分的起止索引。在绝大多数情况下(如键盘输入、粘贴),start为0,end为source.length()。这个范围标识了source中“新”的部分。dest:EditText中当前已经存在的文本内容(Spanned类型,意味着可能包含样式)。dstart&dend: 这是最容易混淆的一对参数。它们定义了dest中即将被source替换的文本范围。- 如果是在光标处插入新字符,那么
dstart == dend,且等于光标在dest中的位置。 - 如果是替换一段选中的文本,那么
dstart是选中部分的起始索引,dend是选中部分的结束索引。 - 如果是删除操作,
source为空字符串(start == end),dstart到dend就是被删除的文本范围。
- 如果是在光标处插入新字符,那么
为了更直观,我们用一个表格来对比几种常见操作下参数的值:
| 操作场景 | EditText原内容 (dest) |
用户输入 (source) |
dstart |
dend |
说明 |
|---|---|---|---|---|---|
| 尾部追加 | “100” | “5” | 3 | 3 | 在“100”后输入“5”,光标在末尾。 |
| 中间插入 | “100” | “.” | 1 | 1 | 在“1”和“00”之间输入小数点,光标在索引1处。 |
| 替换选中 | “100.50” | “0” | 4 | 6 | 选中“.50”(索引4-6),输入“0”。 |
| 删除字符 |


3355

被折叠的 条评论
为什么被折叠?



