当我的InputFilter源代码为可扩展时,该源代码不会删除我筛选出的字符



在这个用例中,我过滤掉了大多数字符和数字。当我键入几个"已筛选"的字符时,比如555,下面每个筛选事件的source中仍然有这5个字符,即使它们已经被筛选掉了。这意味着,在键入555之后,在EditText中没有任何内容出现,我必须退格3次,然后才能真正开始退格EditText中的内容。不仅如此,我的"无效输入"吐司在每个退格上都会触发,因为我的source中仍然有5

因此,如果我键入abc123abc,我的字段会显示abcabc,但记录我的source会显示abc123abc,我会把无效的烤面包扔得到处都是。

过滤器的超类除了一个显示toast的受保护方法之外什么都没有,并且也用于工作的过滤器。

输入滤波器

class TextInputFilter constructor(
private val letters: Boolean,
private val numbers: Boolean,
private val whitespace: Boolean,
private val extraCharacters: Array<Char>,
context: Context?
) : ToastInputFilter(context) {
override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence? {
var valid = true
val builder = StringBuilder()
source.forEach { c ->
if (c.isValid()) {
builder.append(c)
} else {
valid = false
}
}
return if (valid) {
null
} else {
showInputToast(R.string.textInputInvalid)
if (source is Spanned) {
val spannable = SpannableString(builder)
TextUtils.copySpansFrom(source, start, builder.length, null, spannable, 0)
spannable
} else {
builder
}
}
}
private fun Char.isValid(): Boolean {
return when {
isLetter() -> letters
isDigit() -> numbers
isWhitespace() -> whitespace
else -> this in extraCharacters
}
}
}

使用args 实例化

titleEditText.filters = arrayOf(
TextInputFilter(letters = true, numbers = false, whitespace = true, extraCharacters = chars, context = context)
)

我允许的额外字符

chars = safeGetString(R.string.alphaExtraChars).toCharArray().toTypedArray()
<string name="alphaExtraChars">'.-</string>

我已经尝试了我能想到的一切,我还有其他过滤器可以很好地处理数字输入,因为源不是Spannable,只处理新的输入,而不是整个字段。

使用start|end参数后进行编辑,会发生以下情况:

A -> Log: A | Display: A
b -> Log: Ab | Display: Ab
c -> Log: Abc | Display: Abc
1 -> Log: Abc1 | Display: Abc + TOAST
2 -> Log: Abc12 | Display: Abc + TOAST
3 -> Log: Abc123 | Display: Abc + TOAST
Backspace -> Log: Ab | Display: Ab

很好。但是,当我在无效字符之后继续键入有效字符时:

A -> Log: A | Display: A
1 -> Log: A1 | Display: A + TOAST
a -> Log: A1a | Display: Aa + TOAST
1 -> Log: A1a1 | Display: Aa + TOAST
a -> Log: A1a1a | Display: Aaa + TOAST
Backspace -> Log: A1a1 | Display: Aa + TOAST
Backspace -> Log: A | Display: A

我建议简洁地考虑源分隔符:

override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence? {
val builder = StringBuilder()
for (c in source.subSequence(start, end) {
if (c.isValid()) builder.append(c)
}
return if (builder.length == end - start) {
null
} else {
showInputToast(R.string.textInputInvalid)
//...
}
}

如果包含任何无效字符,您可以考虑简化整个过程,以拒绝任何传入的文本块。据推测,您将一次获得一个新字符,或者用户正在粘贴一块文本。是否确实要筛选包含无效字符的文本块?在许多情况下,这将是出乎意料的行为。

因此,如果这样做是可以接受的行为,您的过滤器可以简化为:

override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence? {
for (i in start until end) {
if (!source.charAt(i).isValid()) {
showInputToast(R.string.textInputInvalid)
return ""
}
}
return null
}

最新更新