Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/193.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 当我的InputFilter源作为Spanable输入时,该源不会删除我筛选出的字符_Android_Kotlin - Fatal编程技术网

Android 当我的InputFilter源作为Spanable输入时,该源不会删除我筛选出的字符

Android 当我的InputFilter源作为Spanable输入时,该源不会删除我筛选出的字符,android,kotlin,Android,Kotlin,在这个用例中,我过滤掉了大多数字符和数字。当我输入几个“过滤”字符时,比如说555,下面每个过滤事件的源代码仍然包含这5个字符,即使它们已被过滤掉。这意味着在键入555之后,在EditText中没有显示任何内容时,我必须退格3次,然后才能开始退格EditText中的内容。不仅如此,我的“无效输入”吐司还会在每次退格时触发,因为我的源代码中仍然有5 因此,如果我输入abc123abc,我的字段显示abcabc,但是记录我的源代码显示abc123abc,我会到处扔无效的祝酒词 过滤器的超类除了一个显

在这个用例中,我过滤掉了大多数字符和数字。当我输入几个“过滤”字符时,比如说555,下面每个过滤事件的
源代码仍然包含这5个字符,即使它们已被过滤掉。这意味着在键入555之后,在EditText中没有显示任何内容时,我必须退格3次,然后才能开始退格EditText中的内容。不仅如此,我的“无效输入”吐司还会在每次退格时触发,因为我的
源代码中仍然有5

因此,如果我输入abc123abc,我的字段显示abcabc,但是记录我的
源代码显示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
        }
    }
}
我允许的额外字符

    chars = safeGetString(R.string.alphaExtraChars).toCharArray().toTypedArray()
好。 但是,当我在无效字符后继续键入有效字符时:

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
}

source.forEach
看起来这可能是你的问题。您正在忽略
开始
结束
。我不知道为什么
source
不仅仅是新字符,而且
start
end
都是必需的,但是幕后必须进行一些优化,所以你应该只把
source
中那些索引之间的字符放在你的生成器中。@Tenfour04这是一个很好的观点,但这里有一个有趣的事实:如果我去掉烤面包片,一切都会很完美。而且,如果我在按键之间等待,直到烤面包结束,它也会工作。如果我将toast移到与其他块相同的作用域块之外,同样的事情也会发生,因此它与返回块延迟无关。我认为,当它运行Toast时,源代码会堆积起来并变得不可靠。所以我想没有来自过滤器内部的toast。我将在一个单独的线程中,在对UI上下文所有者的回调中重试toast,而不是在这里执行。它似乎与在过滤器内部运行它有着非常直接的关系。将在我尝试时更新。在您的编辑中,它在您的上一组日志中的行为对我来说是正确的。我错过了什么?您是否不希望在用户按backspace时显示toast?按backspace时,我希望
start==end
这样您就不会到达else块,假设您从未查看过超出该范围的字符。请参阅我对原始问题的编辑-仍处于中断状态。基本问题是,我筛选出的字符由InputFilter/EditText/Spanable/Editable之一保留,并在源代码中返回。因为它是一个文本字段,当我们收到一个Spannable时,它会尝试替换整个字符串,而不仅仅是一个字符。这是因为InputFilter如何处理Spannable与not Spannable,以及为什么它接收一个与另一个。这仍然不能解决它试图用整个条目替换整个字段的问题-对吗?假设有人输入20个有效字符,然后输入一个数字。它会抹去整个田地。因为它使用整个字段作为“源”以替换整个“dest”,所以即使一个字符条目也会擦除整个字段。它仍然可以归结为一个可怕的“源代码是否可扩展”(这是我已经测试过的选项)是吗?这将违反该方法的javadoc。如果你查看输入过滤器.LimthFielter的源代码,他们使用<代码>“”来拒绝更改,他们不考虑源是否是跨越的。这是对我来说,但我会继续探索,看看是否能找到什么。
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
}