How to databind to onTextChanged for an EditText on Android?
Actually it works out of the box. I think my mistake was using an old version of the data binding framework. Using the latest, this is the procedure:
View:
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/username"
android:text="Enter username:"
android:onTextChanged="@{data.onTextChanged}" />
Model:
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.w("tag", "onTextChanged " + s);
}
Make also sure that you have assigned model into DataBinding
For ex. in your activity
lateinit var activityMainDataBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val dataViewModel = ViewModelProvider(this).get(DataViewModel::class.java)
activityMainDataBinding.dataModel = dataViewModel
}
Make sure you are referncing gradle build tools v1.5.0 or higher and have enabled databinding with android.dataBinding.enabled true
in your build.gradle.
edit: Functioning demo project here. view. model.
How to add onTextChanged listener to an include layout xml by databinding in android
You can do it by passing onTextChanged
to included layout. See example -
This is base_edittext_view.xml
<data>
<variable
name="onTextChanged"
type="androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged" />
</data>
<com.google.android.material.textfield.TextInputEditText
...
android:onTextChanged="@{onTextChanged}" />
Now you can pass onTextChanged
to included layout like below.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
layout="@layout/base_edittext_view"
app:onTextChanged="@{(text, start, before, count) -> viewModel.onTextChanged(text)}"/>
</LinearLayout>
-------------That's it!
There can be MANY other ways to implement it. I would like to share you COMPLETE INFORMATION.
WAY 2
You can make another data variable in parent layout. And include it to included layout like above. Like below-
<data>
<variable
name="onTextChanged"
type="androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
layout="@layout/base_edittext_view"
app:onTextChanged="@{onTextChanged}" />
</LinearLayout>
And then you can implement OnTextChanged
in Activity/ViewModel (wherever you need).
binding.setOnTextChanged(new TextViewBindingAdapter.OnTextChanged() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// do you work.
}
});
WAY 3
OR if you don't want take another variable in parent layout, then you can directly pass onTextChanged
to included layout from Java/Kotlin class. See example-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="@+id/includedEditText"
layout="@layout/base_edittext_view"
/>
</LinearLayout>
Then from Java class-
binding.includedEditText.setOnTextChanged(new TextViewBindingAdapter.OnTextChanged() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// your work
}
});
There can be many other ways too. Like making custom method in ViewModel/Activity and call that method from layout.
binding onTextChanged for edit text
Why don't you just use two-way binding with a LiveData
property?
First, add the new email
property to your viewmodel and subscribe to it to receive the changes:
class LoginViewModel(application: Application) : AndroidViewModel(application) {
val email = MutableLiveData<String>()
// This observer will invoke onEmailChanged() when the user updates the email
private val emailObserver = Observer<String> { onEmailChanged(it) }
init {
email.observeForever(emailObserver)
}
override fun onCleared() {
email.removeObserver(emailObserver)
}
fun onEmailChanged(newEmail: String) {
// Some code
}
}
Then, update the view to create a two-way binding between the EditText
and the property email
of your viewmodel:
<EditText
...
android:text="@={viewModel.email}" />
Thanks to the two-way binding, whenever the user updates the text in the view, your viewmodel property will update (and vice versa).
This should hopefully do the trick!
Load drawableLeft image for EditText using databinding when onTextChanged called
you can use custom binding adapter to do so:
first of all, your data should hold some sort of flag you are using to determine email is wrong or not (isValid: Boolean
). You need to update that value every time content inside your editText changes.
in xml you need to introduce property for editText:
<EditText
//properties
app:drawableLeftValidation="@{vm.isValid}"
>
then create custom binding adapter
@BindingAdapter("drawableLeftValidation")
fun setDrawableLeftByValidation(editText: EditText, isValid: Boolean) {
val leftDrawable = if (isValid) {
ContextCompat.getDrawable(editText.context, R.drawable.your_drawable)
} else {
null
}
editText.setCompoundDrawables(leftDrawable, null, null, null)
}
Hope it helped :)
Databinding for TextWatcher is not working Android
According your description of problem, it seems you did not initialized binding in your activity. if this is the case then
First check that you have initialized the binding in your activity and set the ViewModel on it like below
ActivityMainBinding activityMainBinding = null;
PasswordViewModel passwordViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
passwordViewModel = new PasswordViewModel();
activityMainBinding.setViewModel(passwordViewModel);
}
Now the second problem is addTextChangedWatcher
, add addTextChangedListener
in place of that.
like this
public class EditTextBindingAdapters {
@BindingAdapter("textChangedListener")
public static void bindTextWatcher(EditText editText, TextWatcher textWatcher) {
editText.addTextChangedListener(textWatcher);
}
}
how to update textview, ontextchanged in editext using Databinding android
You got ARN because of this line android:text="@={inspect.calculatedTotal}"
Use android:text="@={inspect.calculatedTotal}"
for your EditText
and android:text="@{inspect.calculatedTotal}"
for your TextView
While calculatedTotal
is MutableLiveData
Two-Way databinding in EditText
Thanks to the binding adapters from @LongRanger I was able to advance a lot more in my solution but I had to make some changes on the adapters and in my code. First of all I had to init the ObservableInt member like this:
ObservableInt someNumber;
public ObservableInt getSomeNumber()
{
return someNumber;
}
public void setSomeNumber(ObservableInt number)
{
this.someNumber = number;
}
Second, I had to change the adapters given by @LongRanger to be like this:
@BindingAdapter("android:text")
public static void bindIntegerInText(AppCompatEditText tv, int value)
{
tv.setText(String.valueOf(value));
// Set the cursor to the end of the text
tv.setSelection(tv.getText().length());
}
@InverseBindingAdapter(attribute = "android:text")
public static int getIntegerFromBinding(TextView view)
{
String string = view.getText().toString();
return string.isEmpty() ? 0 : Integer.parseInt(string);
}
That way I avoid the error: Invalid int "", when trying to do Integer.parse(...) on the @InverseBindingAdapter. After this I had to put the cursor on the end of the EditText with the @BindingAdapter, otherwise the cursor kept moving to the start.
Two-way binding Android on edit text
This is not the correct way to use inverse databinding for a view model.
First, EditText
already supports two-way databinding via the databinding library, so you don't have to do this on your own.
Second, you only need the inverse binding adapter stuff if you want to set up a custom view for databinding. In your case, you just want an existing view that is already set up for databinding to update your view moodel.
By using the "@={viewModel.searchKeyword}"
notation, you are indicating that you have a property called "searchKeyword" that has both a getter and a setter and that you want the databinding library to invoke the setter with the value from the view when it changes.
Thus, all you should need to do is implement your logic in your property setter. Something like this:
@Bindable var searchKeyord : String? = null
set(value) {
if (field != value) {
field = value
onSearchEntered(value)
notifyPropertyChanged(BR.searchKeyword)
}
}
Please review the databinding documentation for more info.
Hope that helps!
Related Topics
Pattern "One Activity, Multiple Views": Advantages and Disadvantages
How to Handle Back Button with in the Dialog
Performing Action After Fragment Transaction Animation Is Finished
How to Change the Android App Package Name When Assembling with Gradle
Setrotation(90) to Take Picture in Portrait Mode Does Not Work on Samsung Devices
Dialogfragment with Clear Background (Not Dimmed)
Android:Static Variable Null on Low Memory
How Does Bitmap Allocation Work on Oreo, and How to Investigate Their Memory
Android: Appwidget with Custom View Not Working
How to Customize List Preference Radio Button
Materialcomponents Theme Alert Dialog Buttons
Admob Shows Test Ads But Not Real Ads
Calling Startintentsenderforresult from Fragment (Android Billing V3)
Firebase Cloud Messaging - How to Validate Tokens
Phonegap - Navigator.App.Backhistory() Not Working on HTML Back Button
What Is the Benefit of Using Fragments in Android, Rather Than Views