Checkable CardView in all Android versions
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
- Implement the
Checkable
interface - Merge the
android.R.attr.state_checked
to the drawable states - Use a color selector as background of your
CardView
- Set the
android:foreground
property of theCardView
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 :)