1

I have RecyclerView ,where each item represents, CheckBox and EditText when clicks on CheckBox the text of EditText should strike through, I have ObservableBoolean which is article.complete I used it in app:checkBoxChangeListener="@{article.complete}" app:itemComplete="@{article.complete}"

it works unless I scroll RecyclerView, then clicking on CheckBox another item’s text is strike through 


@BindingAdapter("itemComplete")
public static void bindItemComplete(EditText itemInput, boolean complete){ 
itemInput.setPaintFlags(complete ?
 (itemInput.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG) : 0);
}

Article.java

public class Article{
    public final ObservableBoolean complete = new ObservableBoolean();
}

xml file :

    <?xml version="1.0" encoding="utf-8"?>



<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
  <data>

    <import type="android.view.View" />

    <variable
        name="viewModel"
        type="se.ica.handla.articles.ArticleListViewModel" />

    <variable
        name="article"
        type="se.ica.handla.models.articles.Article" />

</data>

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">

<EditText
android:id="@+id/editText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:itemComplete="@{article.complete}"
/>
<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@={article.complete}" />
</android.support.constraint.ConstraintLayout>
</layout>
I.S
  • 1,904
  • 2
  • 25
  • 48
  • So.. in `bindCheckBox` you want to set thearticles attribute `complete`, am I right? Maybe you can achieve this with [`Two-way-Databinding`](http://stackoverflow.com/documentation/android/111/data-binding-library/6634/built-in-two-way-data-binding#t=201705030857408356564)? `Databinding` works fine for so many people - this may be an error on your side. ;) – yennsarah May 03 '17 at 08:58
  • complete is ObservableBoolean on of the ways to achieve two way binding ,I use complete in app:checkBoxChangeListener="@{article.complete}" for CheckBox and app:itemComplete="@{article.complete}" in EditText , and it works the problem appears during scrolling – I.S May 03 '17 at 13:23
  • You get errors while scrolling, because you set your `complete` to the `view` - and not to the `article` (`view.setTag()...`). And because the views in a `RecyclerView` get *recycled*, the values get messed up when you scroll. The easiest way I see is to use `Two-Way databinding`. Why don't you want to use it? – yennsarah May 03 '17 at 13:27
  • @Amylinn I have updated my question and post my solution it works, but I didn't get the way you are mentioning using view.setTag(), please let me know. – I.S May 03 '17 at 14:52
  • I just quoted your code to make it clearer - sorry if that confused you. I'm glad it works now. I'll add it as an answer, maybe I can get things more clear for you. Also, please don't edit your question code with a solution, it hides the problem for other users and will confuse them. – yennsarah May 04 '17 at 07:42

1 Answers1

0

As written in my comments, I recommend you to use Two-way-Databinding.

You can completely delete this BindingAdapter:

 @BindingAdapter(value = {"checkBoxChangeListener", "article"}, requireAll = false)
 public static void bindCheckBox(CheckBox view, final ObservableBoolean checked, Article article) {     
      if (view.getTag(R.id.binded) == null) {     
          //Here you are setting the attributes to your *view* and 
          //decouple it from your article. It does not reference it, 
          //the properties (isChecked) isnow on the view.               
          //So when your view gets recycled when you scroll, 
          //it still has the property you set the last time - 
          //and not from your current article, which is displayed now in the view. 

          view.setTag(R.id.binded, true);
          view.setOnCheckedChangeListener((buttonView, isChecked) -> checked.set(isChecked));}
      }
 }

As you already found out, your xml should look like this now, using Two-Way Databinding:

<EditText
android:id="@+id/editText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:itemComplete="@{article.complete}"
/>

<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@={article.complete}" //@={} for Two-Way Databinding
/>
Graham
  • 7,431
  • 18
  • 59
  • 84
yennsarah
  • 5,467
  • 2
  • 27
  • 48
  • Yes , I see ,but for this example android:checked="@={article.complete}" @={} works as android:checked is standard attribute but when I want to try it for custom attribute app:focus I could not use @={} app:focus="@{article.focus}" and I have this method and I’m facing the same issues when scrolling @BindingAdapter(“focus”) public static void bindFocus(EditText itemInput, ObservableBoolean focus) { if (focus.get()) { itemInput.requestFocus(); } else { itemInput.clearFocus(); } } – I.S May 04 '17 at 09:11
  • You need an `InverseBindingAdapter` for custom Two-Way Databinding. You can check [George Mounts article](https://medium.com/google-developers/android-data-binding-2-way-your-way-ccac20f6313) about this topic. – yennsarah May 04 '17 at 09:15