I have a custom view that wraps an edit text.
I want the the observe the changes of this edit text at the class that uses this Custom View, using Data Binding.
How can I expose the input string of the edit text to the other classes that use the custom view?
Is two way data binding the only way?
In other XML:
<MyCustomView
android:id="@+id/password_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:password="@={controller.password}"
app:isPasswordValid="@={controller.isValid}"/>
The layout of the custom view (Linear Layout):
<merge>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/security_code_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/email_text_view">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/security_code_edit_text"
android:background="@drawable/edittext_background"
android:inputType="textPassword"
android:text="@={view.pass}"
app:onSubmit="@{() -> view.onKeyboardActionDoneClicked()}" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/textfield_error_invalid_password_length"
app:visibleOrGone="@{view.showInvalidPasswordText}" />
</merge>
If you want to use the xml syntax in your example (app:password="@=controller.password"
), then you need to define static methods for 2-way data binding with @BindingAdapter
and @InverseBindingAdapter
annotations. You can find an official sample here (though I prefer using top-level kotlin extension functions rather than nesting them in an object
since it doesn't require the @JvmStatic
annotation and feels more idiomatic). You can also check out the library source for how 2-way binding adapters are defined for TextView
here, though it's probably more involved than what you'd need to do for your case.
If all you need to do is observe text changes and you don't need to set the text directly on your custom view, then 2-way data binding is unnecessary and you can set some sort of listener that will call back when the text changes (which could be set via data binding if you have a public setter) or expose a LiveData<String>
that you can observe (not using xml/data binding).
I can think of 2 ways of doing this
@BindingAdapter("bind:doSomething") fun bindDoSomething( view: EditText, vm: ViewModel? ) { vm?.let { view.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun afterTextChanged(s: Editable?) { } override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { vm.callFun() } }) } }
and in your xml:
app:doSomething="@{vm}"
Let me know if this helps or if you have any questions
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With