EditText 经常会有限制输入字符长度的需求,限制输入长度的方法有三种:
- xml设置maxLength属性
1
2android:maxLength="50"
- 通过InputFilter过滤长度
1
2
3EditText editText = (EditText)findViewById(R.id.edit); editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(10)});
实际上在XML 中设置,最后也是通过设置InputFilter 实现的,LengthFilter 只是实现了字符串长度
的限制。
- 为EditText设置 TextWatcher 监听
自定义MyTextWatcher类,实现TextWatcher 接口,监听EditText 的文本变化,手动对输入文本进行截断。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32EditText editText = findViewById(R.id.edit); editText.addTextChangedListener(new MyTextWatcher(editText, 10)); private class MyTextWatcher implements TextWatcher { private EditText editText; private int maxCount; MyTextWatcher(EditText editText, int maxCount) { this.editText = editText; this.maxCount = maxCount; } @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) { if (s.length() > maxCount) { editText.setText(s.subSequence(0, maxCount)); Selection.setSelection(editText.getText(), maxCount); } } }
关于编码
Java编译器默认使用Unicode编码,因此2字节(16位)可以表示所有字符。
Java基本类型占用的字节数:
1字节: byte , boolean
2字节: short , char
4字节: int , float
8字节: long , double
注:1字节(byte)=8位(bits)
编码与字符:
通常一个字符相当于一个字节,但是根据编码不同,一个字符也可能等于两个或者三个字符。
Unicode/GBK: 中文2字节
UTF-8: 中文通常3字节,在拓展B区之后的是4字节
InputFilters介绍
InputFilters用在可编辑的控件,用来限制控件的变化。
1
2
3
4
5
6
7
8
9
10
11//InputFilter只有一个filter方法 public CharSequence filter(CharSequence source, int start, int end,Spanned dest, int dstart, int dend); //filter参数介绍: source :变化的字符串 start :变化字符的首字符下标 end :变化字符的尾字符下 dest :带光标的字符串 dstart :光标的起始位置 dend :光标的结束位置
filter方法返回的是一个CharSequence,用来控制可编辑控件添加字符时的约束条件。主要分为三种情况:
- 返回null:表示可正常添加source字符串;
- 返回"":表示不变动原字符;
- 返回以上之外的字符串:表示将返回的该字符串追加到原字符串中。
maxLength属性限制的是输入的
字符长度
,而不是字节长度,如果我们想要限制字符串的字节长度
,可以自己实现InputFilter 接口来实现相应功能。通过使用如下工具类,可以实现EditText输入的最大字节长度。
1
2editText.setFilters(new InputFilter[]{new Utf8ByteLengthFilter(10)});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49packages/apps/Settings/src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java public class Utf8ByteLengthFilter implements InputFilter { private final int mMaxBytes; @Keep Utf8ByteLengthFilter(int maxBytes) { mMaxBytes = maxBytes; } public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { int srcByteCount = 0; // count UTF-8 bytes in source substring for (int i = start; i < end; i++) { char c = source.charAt(i); srcByteCount += (c < (char) 0x0080) ? 1 : (c < (char) 0x0800 ? 2 : 3); } int destLen = dest.length(); int destByteCount = 0; // count UTF-8 bytes in destination excluding replaced section for (int i = 0; i < destLen; i++) { if (i < dstart || i >= dend) { char c = dest.charAt(i); destByteCount += (c < (char) 0x0080) ? 1 : (c < (char) 0x0800 ? 2 : 3); } } int keepBytes = mMaxBytes - destByteCount; if (keepBytes <= 0) { return ""; } else if (keepBytes >= srcByteCount) { return null; // use original dest string } else { // find end position of largest sequence that fits in keepBytes for (int i = start; i < end; i++) { char c = source.charAt(i); keepBytes -= (c < (char) 0x0080) ? 1 : (c < (char) 0x0800 ? 2 : 3); if (keepBytes < 0) { return source.subSequence(start, i); } } // If the entire substring fits, we should have returned null // above, so this line should not be reached. If for some // reason it is, return null to use the original dest string. return null; } } }
此方法来自与设置-关于手机中设备名称的EditText限制逻辑,原生逻辑是限制30个字节,汉字为3个字节,字母或数字为1个字节,中文标点符号为3个字节,英文标点符号为1个字节,空格为1个字符,即最大输入汉字为10个或英文为30个。但是EditText可输入emoji表情,1个emoj为6个字节,此时当输入9个汉字+1个emoji时,根据Utf8ByteLengthFilter逻辑会过滤掉半个emoji,此时设备名称会失败保存,因为设备名称和蓝牙/WIFI热点名称一致,当 setSsid(@Nullable String ssid)
时会checkArgument失败 Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid));
,主要问题是此处的逻辑,会拼接上剩余字节数的字符:
1
2
3
4
5
6
7
8for (int i = start; i < end; i++) { char c = source.charAt(i); keepBytes -= (c < (char) 0x0080) ? 1 : (c < (char) 0x0800 ? 2 : 3); if (keepBytes < 0) { return source.subSequence(start, i); } }
解决方法:
1
2
3
4
5
6
7if (keepBytes >= srcByteCount) { return null; } else { // 可以加上Toast:输入已达上限 return ""; }
最后
以上就是如意狗最近收集整理的关于Android EditText输入限制及字符编码的全部内容,更多相关Android内容请搜索靠谱客的其他文章。
发表评论 取消回复