haagantos
haagantos

Reputation: 21

How to change background color of CardView depending if is selected or not?

I'm trying to change the color of a CardView depending if is selected or not

I tried this, this is my card_view_color.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true"
        android:color="#ABEBC6"/> <!-- selected -->
    <item android:state_selected="false"
        android:color="#FFFFFF"/> <!-- not selected -->
</selector>

This is my CardView:

<androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:cardBackgroundColor="@color/card_view_color"
        android:id="@+id/cardViewMetric">
</androidx.cardview.widget.CardView>

Also tried with android:state_activated, android:state_checked and is the same result, not working.

I also have a onClickListener (Kotlin):

holder.binding.root.setOnClickListener{
            val GREEN_COLOR = Color.parseColor("#ABEBC6") 
            holder.binding.cardViewMetric.setCardBackgroundColor(GREEN_COLOR)
        }

That has this current behavior.
this

The wanted behavior I want is only one CardView is gonna be colored, and if I select another one that one is gonna be green and the previous selection is gonna be white.

Upvotes: 2

Views: 4673

Answers (3)

Muhammad Ammar
Muhammad Ammar

Reputation: 1283

Here's the kotlin way :

create an extension function like that:

fun MaterialCardView.managePressed(onClick: () -> Unit) {
    this.setOnTouchListener { v, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                this.setCardBackgroundColor(context.mutedColor(R.color.onpressed_color))
            }
            MotionEvent.ACTION_UP -> {
                this.setCardBackgroundColor(context.mutedColor(R.color.on_clicked_done_color))
                onClick.invoke()
            }
            MotionEvent.ACTION_CANCEL -> {
                this.setCardBackgroundColor(context.mutedColor(R.color.default_color))
            }
            else -> {
            }
        }
        false
    }

Usage:

yourCardView.managePressed() {
//click_listner_call_back_will_be_here
}

Upvotes: 0

haagantos
haagantos

Reputation: 21

Thanks to the answer of Gabriele Mariotti it gave me an idea:

I changed my CardView to:

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:cardBackgroundColor="@color/card_view_color"
        android:focusableInTouchMode="true"
        android:id="@+id/cardViewMetric">
    </androidx.cardview.widget.CardView>

(added the focusableInTouchMode attribute)

And in my card_view_color.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true"
        android:color="#ABEBC6"/> <!-- selected -->
    <item android:state_focused="false"
        android:color="#FFFFFF"/> <!-- not selected -->
</selector>

And now it has the wanted behavior

EDIT: forgot to say that setOnClickListener is not needed

Hope it helps to anyone=)

Upvotes: 0

Gabriele Mariotti
Gabriele Mariotti

Reputation: 364868

You can use the MaterialCardView in the Material Components Library.

<com.google.android.material.card.MaterialCardView
    ...
    app:checkedIcon="@null"
    android:clickable="true"
    android:focusable="true"
    android:checkable="true">
    
</com.google.android.material.card.MaterialCardView>

Then in your code:

    card.setChecked(true)
    

The MaterialCardView extends the androidx.cardview.widget.CardView and support the checking state.

To customize the color you can use the app:cardForegroundColor attribute:

    <com.google.android.material.card.MaterialCardView
        app:cardForegroundColor="@color/card_selector"

with:

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:alpha="...."  android:color="@color/..." android:state_checked="true"/> 
    <item android:alpha="...."  android:color="@color/..." app:state_dragged="true"/>
    <item android:color="@android:color/transparent" android:state_checked="false" app:state_dragged="false"/>
</selector>

or you can override the colorPrimary in the card:

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/card"
        style="@style/Widget.MaterialComponents.CardView"

with:

<style name="ThemeOverlay.CardView" parent="">
    <item name="colorPrimary">@color/....</item>
</style>

By default the checked card has also a checked icon on the top right corner. You can customize it using the app:checkedIcon attribute or you can hide it using app:checkedIcon="@null".

enter image description here

Upvotes: 1

Related Questions