I have three TextInputEditText
views in my layout where the user can type in specific information.
On the click of a Button
this information is stored in my database.
After the user clicks this Button
, I want to clear all TextInputEditText
fields.
Right now, I am doing this by hardcoding:
private fun clearAllEditTextFields() {
Timber.d("clearAllEditTextFields: called")
binding.bookTitleEditText.text = null
binding.bookAuthorEditText.text = null
binding.bookPageCountEditText.text = null
}
Since this is bad, I would like to use a dynamic for each
loop to identify all views of type TextInputEditText
known to binding
and clear their content:
private fun clearAllEditTextFields() {
Timber.d("clearAllEditTextFields: called")
for (view in binding.views) {
if (view is TextInputEditText) {
view.text = null
}
}
Unfortunately, there is no such field binding.views
.
Is there still a way to achieve this or something with the same properties?
I have used a BindingAdapter
. In my Util
class, where all my extension functions go, I have created an EditText
extension function clearText
annotated as BindingAdapter
and JvmStatic
:
@JvmStatic
@BindingAdapter("clearText")
fun EditText.clearText(@NotNull shouldClear: Boolean) {
Timber.d("clearText: called")
if (shouldClear) text = null
}
In XML:
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/book_title_edit_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:imeActionId="100"
android:imeOptions="actionNext"
android:inputType="text"
android:text="@={viewModel.bookTitle}"
app:clearText="@{viewModel.clearAllEditTextFields}"
/>
In my ViewModel
class, I have created a var clearAllEditTextFields = false
which is modified in the clearAllEditTextFields()
function which gets called inside my ViewModel
:
...
var clearAllEditTextFields = false
clearAllEditTextFields()
...
private fun clearAllEditTextFields() {
Timber.d("clearAllEditTextFields: called")
clearAllEditTextFields = true
}
According to Logcat, my extension function is called when my ViewModel
is initialized. However, when clearAllEditTextFields()
gets called, it does not trigger a new call to the extension function.
A simple for
loop doesn't exist to loop over the views in the binding
object and you can try the following to keep your code conscice.
Scope Functions
binding.apply{
bookTitleEditText.text = null
bookAuthorEditText.text = null
bookPageCountEditText.text = null
}
scope functions are a good go iff there are few views and we end up with quite a boiler-plate
code if the number of views is large, in which cases I think Binding-Adapter
would be a good choice
@BindingAdapter("clear_text")
fun EditText.clearText(shouldClear : Boolean?){
shouldClear?.apply{
if(shouldClear)
text = null
}
}
ViewModel
private val _shouldClear = MutableLiveData<Boolean>()
val shouldClear : LiveData<Boolean>
get() = _shouldClear
fun setClearStatus(status : Boolean){
_shouldClear.value = status
}
//since clearing a text is an event and not state, reset the clear_status once it's done
fun resetClearStatus(){
_shouldClear.value = nul
}
XML
<EditText
......
app:clear_text = "@{yourViewModel.shouldClear}"
...... />
ActivityClass
...
binding.lifecycleOwner = this
...
private fun clearAllEditTextFields() {
yourViewModel.setClearStatus(true)
yourViewModel.resetClearStatus()
}
Edit:
add binding.lifecycleOwner = this
in your activity class and its used for observing LiveData with data binding. The view will observe for text changes at runtime.