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
class ControlledTextWatcher(
private val parent: TextView,
private val onChange: ((text: CharSequence?, start: Int, before: Int, count: Int) -> Unit)?,
private val beforeChange: ((text: CharSequence?, start: Int, count: Int, after: Int) -> Unit)? = null,
private val afterChange: ((editable: Editable?) -> Unit)? = null
) : TextWatcher {
init {
parent.addTextChangedListener(this)
}
private var enabled = true
var text: String?
get() = parent.value
set(value) {
this.enabled = false
parent.text = value
this.enabled = true
}
var res: Int
get() = throw RuntimeException("String resource cannot be retrieved after being set")
set(value) {
parent.text = parent.context.getString(value)
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
if (enabled)
beforeChange?.invoke(s, start, count, after)
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (enabled)
onChange?.invoke(s, start, before, count)
}
override fun afterTextChanged(s: Editable?) {
if (enabled)
afterChange?.invoke(s)
}
fun detach() {
parent.removeTextChangedListener(this)
}
}
and I use it mainly with view bindings like so
class TestActivity : AppCompatActivity() {
class TestActivity : AppCompatActivity() {
private lateinit var binding: ActivityTestBinding
private val edit by lazy { ControlledTextWatcher(binding.text, this::textChanged }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTestBinding.inflate(layoutInflater)
setContentView(binding.root)
}
so when I wish to make changes to the actual EditText
I use the text
or res
attribute of the ControlledTextWatcher
like so:
edit.text = "hello world" //this does not trigger the text watcher
but when the user alters the EditText
it will trigger
unfortunatelly with this solution if you want to alter other parameters of the EditText
, you either have to get the original EditText
through bindings or copy those functions to the ControlledTextWatcher
also you have to be careful when making changes in afterChange
because the change is posted to the TextView
so you may end up with an endless loop