Android checkboxes not checked correctly in ViewPa

2020-03-20 16:48发布

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.

标签: android
4条回答
对你真心纯属浪费
2楼-- · 2020-03-20 17:14

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

查看更多
Ridiculous、
3楼-- · 2020-03-20 17:23

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).

查看更多
Deceive 欺骗
4楼-- · 2020-03-20 17:25

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.

查看更多
家丑人穷心不美
5楼-- · 2020-03-20 17:35

same same me,,, but I have idea,,

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.page_mynotification_call, container, false);

    checkbox = (CheckBox) view.findViewById(R.id.checkbox_call);
    checkbox.setChecked(true);

    return view;
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
}

set checkbox is in onCreateView, not onViewCreated na,

thank you,

查看更多
登录 后发表回答