How to Databind to Ontextchanged for an Edittext on Android

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



Leave a reply



Submit