I'm creating a form on an android application using kotlin. Each field of the form is associated with a livedata, to validate or update the data instantly. To obtain this result, I used a textwatcher, which updates the associated livedata at each change of the text. The problem is that with each update, it places the cursor at the start of the field making it impossible to write continuously.
I paste here the intresting part of the code:
Activity
viewModel.name.observe(lifecycleOwner, Observer { nameValue->
binding.nameEditText.setText(
nameValue?.toString()
)
binding.nameTextInputLayout.error =
viewModel.nameError.value
})
viewModel.price.observe(lifecycleOwner, Observer { priceValue->
binding.priceEditText.setText(
price?.toString()
)
binding.priceTextInputLayout.error =
viewModel.priceError.value
})
binding.nameEditText.addTextChangedListener(
TextFieldValidation(
binding.nameEditText
)
)
binding.priceEditText.addTextChangedListener(
TextFieldValidation(
binding.priceEditText
)
)
inner class TextFieldValidation(private val view: View) : TextWatcher {
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
when (view.id) {
R.id.nameEditText-> {
viewModel.onNameChanged(s.toString())
viewModel.isNameValid()
}
R.id.priceEditText-> {
viewModel.onPriceChanged(s.toString())
viewModel.isPriceValid()
}
}
}
ViewModel
var name = MutableLiveData<String>()
var price = MutableLiveData<Double>()
var nameError = MutableLiveData<String>()
var priceError = MutableLiveData<String>()
fun onNameChanged(newValue: String?) {
if ((name.value != newValue)) {
name.value = newValue
}
}
fun onPriceChanged(newValue: Double?) {
if ((price.value != newValue)) {
price.value = newValue
}
}
fun isNameValid() : Boolean {
return if ((name.value == null) || (name.value == "")) {
nameError.value = "Error"
false
} else {
nameError.value = ""
true
}
}
fun isPriceValid() : Boolean {
return if ((price.value == null) || (price.value == "")) {
priceError.value = "Error"
false
} else {
priceError.value = ""
true
}
}
XML
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/nameTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/nameEditText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:backgroundTint="@color/white"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/priceTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/priceEditText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:backgroundTint="@color/white"
android:inputType="numberDecimal" />
</com.google.android.material.textfield.TextInputLayout>
I tried using 'mEdittext.setSelection (mEdittext.length ());' but it doesn't work well, because if I make changes in the middle of the string, it brings the cursor to the end. And even in double fields, it doesn't behave correctly. I need to have the cursor always at the exact position? Either in case of adding, deleting or writing in the middle of the string. And both in the case of a string and in the case of a double.
Could someone help me?
Thank you for your patience and help!