Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android checkboxes not checked correctly in ViewPager with data binding

Tags:

android

I have a form in my Android app that is spread across multiple pages with a ViewPager.

To keep it simple, it just returns View-objects instead of instantiating Fragments.

Each view is made of a layout and a viewmodel (The same instance I use for all the views) and data binding to set the values automatically.

The problem is that the checkboxes is not filled and have a white checkmark if they are in a view that is not in the front when loading the activity.

If I change the order, so my view with the checkboxes are the first one loaded by the ViewPager, I can see the checkboxes being checked (with an animation) and they are marked correctly.

See the attached screenshots:

View not being the first loaded

View being the first loaded

I have the same problem with radio buttons.

An example of a Checkbox's databinding:

<CheckBox
            android:id="@+id/checkbox_calling"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:layout_weight="1"
            android:checked="@={viewModel.observation.calling}"
            android:text="@string/label_calling" />

UPDATE:

I have currently solved the problem by setting a OnPageChangeListener on the ViewPager and when the ViewPager scrolls to the page with the checkboxes, I uncheck the checkboxes and then set them to the original value.

The animation is then shown correctly and the checkboxes ends up with the correct checkmarks.

I would however still appreciate finding out what I've done wrong or if there is a problem with Android databinding itself.

like image 626
Anders Olsen Avatar asked Mar 24 '17 09:03

Anders Olsen


3 Answers

I think that it has to do with the way checkbox are animated. So I looked up how to skip the animation, and calling jumpDrawablesToCurrentState on the checkbox after checking it does the trick for me.

like image 166
Vivere Discere Avatar answered Nov 14 '22 19:11

Vivere Discere


I created this Kotlin extension property to deal with the problem (obviously only useful if you are writing Kotlin code, not Java)

/**
 * Set the state of a checkbox skipping animations.
 */

var CheckBox.checked: Boolean
    get() = isChecked
    set(value) {
        if(isChecked != value) {
            isChecked = value
            jumpDrawablesToCurrentState()
        }
    }

Now in my code I write checkbox_view.checked = true instead of checkbox_view.isChecked = true

like image 33
Clyde Avatar answered Nov 14 '22 19:11

Clyde


The accepted answer from Vivere explains the issue and solution perfectly.

The extended solution from Clyde is a great idea, but it caused issues for me. With some little tweaks I fixed it.

My final piece of code:

/**
 * Do not animate the check, but check it directly, due to issue in combination with ViewPager:
 * https://stackoverflow.com/questions/42997873/android-checkboxes-not-checked-correctly-in-viewpager-with-data-binding
 */
var CompoundButton.isCheckedInViewPager: Boolean
    get() = isChecked
    set(value) {
        if (isChecked != value) {
            isChecked = value
        }
        jumpDrawablesToCurrentState()
    }

What was my issue with Clyde's code?

My Checkbox is located on the 3rd page of the ViewPager. To visualise what happened I added some logs:

var CompoundButton.isCheckedInViewPager: Boolean
    get() = isChecked
    set(value) {
        Log.d("TEST", "set")
        if (isChecked != value) {
            Log.d("TEST", "value: $value")
            Log.d("TEST", "isChecked: $isChecked")
            isChecked = value
            Log.d("TEST", "isChecked: $isChecked")
        }
        jumpDrawablesToCurrentState()
    }

Logs:

// Navigate from page 1 to page 2 (page 3 with the checkbox is loaded due to the ViewPager):
...: set
...: value: true
...: isChecked: false
...: isChecked: true
// Navigate to page 3 to verify the checkbox's visual state
// Navigate back to page 1 and forward to page 2 again
...: set
// Navigate to page 3 to verify the checkbox's visual state

So when I navigate to the checkbox the first time it'll all be allright. If I navigate back to the 1st and to the 3rd again, the checkbox is unchecked again in Clyde's solution, because if (isChecked != value) is false: jumpDrawablesToCurrentState will not be called and the issue arises nonetheless.

ps. for clarity's sake: the checkbox will be checked onViewCreated by observing a LiveData<Boolean> in my ViewModel. This value is true by default, so the checkbox should be checked.


Note:

Next to solving the issue with this code, I extended CompoundButton to support RadioButtons as well.

Finally, the name isCheckedInViewPager describes better when to use it, and won't be forgotten so easily if another developer starts calling isChecked (thanks to autocomplete).

like image 1
P Kuijpers Avatar answered Nov 14 '22 18:11

P Kuijpers