Checkable CardView in all Android versions

Albin Poignot
3 min readJun 12, 2017

Recently, I tried to get a CardView to like a CheckBox : I wanted it to be clickable and checkable - and so providing a feedback to the user if it is “checked” or not.

Since CardView comes from the Support Library, I struggled a bit finding any valuable documentation. Here is a simple solution to get a checkable CardView with a background color selector.

The steps

  1. Implement the Checkable interface
  2. Merge the android.R.attr.state_checked to the drawable states
  3. Use a color selector as background of your CardView
  4. Set the android:foreground property of the CardView to ?android:attr/selectableItemBackground

1st step : implementing Checkable

Implementing the Checkable interface is pretty straight forward : you have to store the checked state of your view by yourself.

public class CheckableCardView extends CardView 
implements Checkable {
// Constructors and view initialization private boolean isChecked = false; @Override
public boolean performClick() {
toggle();
return super.performClick();
}
@Override
public void setChecked(boolean checked) {
this.isChecked = checked;
}
@Override
public boolean isChecked() {
return isChecked;
}
@Override
public void toggle() {
setChecked(!this.isChecked);
}
}

2nd step : merging drawable states

The checked state is used by drawables. View classes provided by Android SDK handle states (pressed, focused, etc…) by themselves and so we generally don’t see them.

As a CardView is initially not checkable, it does not handle the checked state. You will have to manually handle it.

Statically stores the state you want to add to your drawable:

private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked,
};

Then override this method:

@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState =
super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}

This method check if the card is checked or not. If it is, it adds the state_checked to the current drawable states (and if not, we are just doing nothing). After that, the CardView will have the state_checked set to true, and so the selector will be able to do its job correctly.

3rd step : the ColorStateList

You now have to declare the color to use in the different states:

res/color/selector_card_view_colors.xml

<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">

<item android:color="#CE93D8"
android:state_pressed="true" />
<item android:color="#E1BEE7"
android:state_checked="true" />
<item android:color="#F3E5F5" /></selector>

You also need to use it in your CardView class. Add this where you initialize your class:

setCardBackgroundColor(
ContextCompat.getColorStateList(
getContext(),
R.color.selector_card_view_background
)
);

4rd step : setting the foreground for newer API

The last step is pretty easy. You just need to declare that your CardView foreground is selectable.

To do this, you just have to declare your CardView this way:

<com.example.checkablecardview.CheckableCardView
android:layout_width="@dimen/card_width"
android:layout_height="@dimen/card_height"
android:foreground="?android:attr/selectableItemBackground" />

And that’s it ! Your CardView class is now checkable :) You just have to use it instead of the SDK provided CardView class.

Conclusion

Keep in mind that the way I presented here is a really basic one. You could improve it by using styles, not hardcoding colors, etc…

You can find an exemple project containing the code used in this article in the link below. All pull requests, comments, ideas… are welcome :)

Sources

--

--