如何在不触发文本观察器的情况下更改 EditText 文本?
我有一个 EditText
字段,上面有一个客户文本观察器。在一段代码中,我需要更改 EditText 中的值,我使用 .setText("whatever")
执行此操作。
问题是,一旦我进行更改,afterTextChanged
方法就会被调用,这会创建一个无限循环。如何更改文本而不触发 afterTextChanged?
我需要 afterTextChanged 方法中的文本,因此不建议删除 TextWatcher
。
I have an EditText
field with a Customer Text Watcher on it. In a piece of code I need to change the value in the EditText which I do using .setText("whatever")
.
The problem is as soon as I make that change the afterTextChanged
method gets called which created an infinite loop. How can I change the text without it triggering afterTextChanged?
I need the text in the afterTextChanged method so don't suggest removing the TextWatcher
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
简短回答
您可以检查当前哪个视图具有焦点,以区分用户触发的事件和程序触发的事件。
长答案
作为简短答案的补充:
如果以编程方式更改文本时
myEditText
已经获得焦点,则应调用clearFocus()
,然后调用setText(...)
然后你重新请求焦点。将其放入实用函数中是一个好主意:对于 Kotlin:
由于 Kotlin 支持扩展函数,因此您的实用函数可能如下所示:
Short answer
You can check which View currently has the focus to distinguish between user and program triggered events.
Long answer
As an addition to the short answer:
In case
myEditText
already has the focus when you programmatically change the text you should callclearFocus()
, then you callsetText(...)
and after you you re-request the focus. It would be a good idea to put that in a utility function:For Kotlin:
Since Kotlin supports extension functions your utility function could look like this:
您可以取消注册观察者,然后重新注册。
或者,您可以设置一个标志,以便您的观察者知道您自己何时刚刚更改了文本(因此应该忽略它)。
You could unregister the watcher, and then re-register it.
Alternatively, you could set a flag so that your watcher knows when you have just changed the text yourself (and therefore should ignore it).
Java:
Kotlin:
用法:
如果您使用 editText.setText() 而不是 editable.replace(),则在快速输入文本时可能会感到有点滞后。
Java:
Kotlin:
Usage:
You may feel a little bit lag when entering text rapidly if you are using editText.setText() instead of editable.replace().
修复的简单技巧...只要派生新编辑文本值的逻辑是幂等的(它可能是,但只是说)。在侦听器方法中,仅当当前值与上次修改值不同时才修改编辑文本。
例如,
Easy trick to fix ... as long a your logic to derive the new edit text value is idempotent (which it probably would be, but just saying). In your listener method, only modify the edit text if the current value is different than the last time you modified the value.
e.g.,
您可以使用 Kotlin DSL 语法来获得通用解决方案:
在 TextWatcher 中,您可以将其用作:
You can use Kotlin DSL syntax to have the generic solution for this:
And inside your TextWatcher, you can use it as:
我这样使用:
每次需要以编程方式更改文本时,首先清除焦点
I use that way:
And every time you need to change text programatically, first clear the focus
使用
tag
提交可以轻松解决该问题,您甚至不必处理 editText 的焦点。以编程方式设置文本和标签
检查 onTextChanged 中的
标签
The problem can be easily solved using
tag
filed and you don't even have to deal with editText's focus.Setting the text and the tag programmatically
Checking for the
tag
in onTextChanged这对我来说很有用
This works good for me
如果您需要专注于
EditText
更改文本,您可以请求焦点:If you need to stay focused on
EditText
change text you could request focus:很简单,这样做
就不会无限循环
It's easy just do it like this
in this way it don't stock in infinite loop
试试这个逻辑:
我想 setText("") 而不进入无限循环,这段代码对我有用。我希望您可以修改此以满足您的要求
try this logic:
I wanted to setText("") without going to infinite loop and this code works for me. I hope you can modify this to fit your requirement
这是一个方便的类,它提供了比 TextWatcher 更简单的接口,适用于想要查看发生的更改的正常情况。它还允许忽略 OP 请求的下一个更改。
像这样使用它:
每当您想要修改
editText
的内容而不引起一连串的递归编辑时,请执行以下操作:Here's a handy class that provides a simpler interface than TextWatcher for the normal case of wanting to see changes as they occur. It also allows for ignoring the next change as the OP requested.
Use it like this:
Whenever you want to modify the contents of
editText
without causing a cascade of recursive edits, do this:我的变体:
仅使用 setOnTextChangeListener() 设置侦听器,仅使用 setNewText 设置文本(我想覆盖 setText(),但它是最终的)
My variant:
Set listeners only using setOnTextChangeListener() and set text only using setNewText (I wanted to override setText(), but it is final)
我创建了一个抽象类,它可以缓解通过 TextWatcher 修改 EditText 时出现的循环问题。
I've created an abstract class which mitigates the cyclic issue of when a modification to the EditText is made via a TextWatcher.
很简单,用这个方法设置文本
Very simple, set text with this method
我的解决方案与其他解决方案非常相似,只是它是我使用视图绑定对其进行自定义旋转,
我创建了以下 TextWatcher
,我主要将它与视图绑定一起使用,例如
class TestActivity : AppCompatActivity() {
因此,当我希望更改实际的
EditText
我使用ControlledTextWatcher
的text
或res
属性,如下所示:但是当用户更改
EditText
不幸的是,如果您想更改EditText
的其他参数,此解决方案将触发,您必须通过绑定获取原始
EditText
或者将这些函数复制到ControlledTextWatcher
中,在
afterChange
中进行更改时也必须小心,因为更改会发布到TextView
中,因此您可以最终陷入无限循环My solution for this is a lot like the others only it's my custom spin on it using viewbindings
I created the following TextWatcher
and I use it mainly with view bindings like so
class TestActivity : AppCompatActivity() {
so when I wish to make changes to the actual
EditText
I use thetext
orres
attribute of theControlledTextWatcher
like so:but when the user alters the
EditText
it will triggerunfortunatelly with this solution if you want to alter other parameters of the
EditText
, you either have to get the originalEditText
through bindings or copy those functions to theControlledTextWatcher
also you have to be careful when making changes in
afterChange
because the change is posted to theTextView
so you may end up with an endless loop您应该确保文本更改的实现是稳定的,并且如果不需要更改,则不会更改文本。通常,这将是观察者已经浏览过一次的任何内容。
最常见的错误是在关联的 EditText 或 Editable 中设置新文本,即使文本实际上并未更改。
最重要的是,如果您对可编辑而不是某些特定视图进行更改,您可以轻松地重新使用您的观察者,并且您还可以通过一些单元测试单独测试它,以确保它具有您想要的结果。
由于 Editable 是一个接口,您甚至可以使用它的虚拟实现,如果在测试应该稳定的内容时调用其任何方法来尝试更改其内容,则该实现会抛出 RuntimeException。
You should ensure your implementation of text changes is stable and does not change the text if no change is needed. Normally that would be any content that's already been through the watcher once.
The most common mistake is to set a new text in the associated EditText or the Editable even though the text was not actually changes.
On top of that, if you make your changes to the Editable instead of some specific View, you can easily resuse your watcher, and also you can test it in isolation with some unit tests to ensure it has the outcome you want.
Since Editable is an interface you could even use a dummy implementation of it that throws a RuntimeException if any of its methods are called that try to change its contents, when testing content that should be stable.
我的做法是:
在写入段中,
侦听器
无论如何都可以工作。
My way to do the thing:
In the write segment
The listener
Works anyway.