Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CardView's background which will respond to android:state_selected and android:state_pressed

Tags:

android

I'm referring to the answer at https://stackoverflow.com/a/24475228/72437

The proposed answer is using drawable from Android : ?android:attr/selectableItemBackground

enter image description here

This is what happen when I tap on the card item. Note that, by using drawable from Android, android:state_selected="true" (when setSelected(true)) will not have any color change effect.

Hence, I would like to use my own defined drawable so that

  1. It looks nicer.
  2. Able to handle android:state_selected="true".

Here's my code


statelist_item_background.xml

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

    <item android:state_pressed="true" android:drawable="@drawable/selected_background" />
    <item android:state_selected="true" android:drawable="@drawable/selected_background" />
    <item android:drawable="@android:color/transparent" />

</selector>

selected_background.xml

<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ffffe1b3" />
    <stroke
        android:width="1px"
        android:color="#fff76d3c" />
</shape>

card_row.xml

<!-- A CardView that contains a TextView -->
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="5dp"
    android:layout_marginBottom="5dp"
    android:clickable="true"
    android:foreground="@drawable/statelist_item_background"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:padding="5dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/txt_label_item"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            tools:text="Item Number One" />

        <TextView
            android:id="@+id/txt_date_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            tools:text="Item Number One" />
    </LinearLayout>
</android.support.v7.widget.CardView>

When I long press on the card item and perform childView.setSelected(true);, here's my outcome.

enter image description here

All my card content (TextViews) are blocked. How can I avoid such?

Some notes regarding using android:background

Note, when you use android:background="@drawable/statelist_item_background" with CardView itself, nothing will happen.

However, if you use android:background="@drawable/statelist_item_background" with CardView's LinearLayout, you will get the following imperfect outcome.

enter image description here

The highlighted color doesn't cover the entire card.

Update

Seem like this is limitation of CardView - https://code.google.com/p/android/issues/detail?id=78198 Using "foreground" as workaround is not an option as it covers card content.

like image 439
Cheok Yan Cheng Avatar asked Oct 20 '25 09:10

Cheok Yan Cheng


2 Answers

After experimenting for quite some time, I can pretty much conclude that this is limitation of current CardView - https://code.google.com/p/android/issues/detail?id=78198

Don't use CardView's foreground workaround. Although it is widely being proposed, it just don't work!

My suggestion is, avoid using CardView if you need a customized selector. Replace it LayerDrawable. Here's what I had done.

card.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="@android:color/transparent" />
            <stroke
                android:width="1dp"
                android:color="#ffededed" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke
                android:width="1dp"
                android:color="#ffe8e8e8" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item>
        <shape>
            <padding android:top="0dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke
                android:width="1dp"
                android:color="#ffe1e1e1" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item>
        <shape>
            <padding android:top="0dp" android:right="0dp" android:bottom="1dp" android:left="0dp" />
            <stroke
                android:width="1dp"
                android:color="#ffdbdbdb" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item>
        <shape>
            <padding android:top="0dp" android:right="0dp" android:bottom="1dp" android:left="0dp" />
            <stroke
                android:width="1dp"
                android:color="#ffd5d5d5" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <!--
    <item>
        <shape>
            <padding android:top="0dp" android:right="0dp" android:bottom="1dp" android:left="0dp" />
            <stroke
                android:width="1dp"
                android:color="#ffcfcfcf" />
            <corners android:radius="2dp" />
        </shape>
    </item>
    -->

    <item>
        <shape >
            <solid android:color="#ffffffff" />
            <corners android:radius="2dp" />
        </shape>
    </item>
</layer-list>

card_selected.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke
                android:width="1dp"
                android:color="#ffededed" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke
                android:width="1dp"
                android:color="#ffe8e8e8" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item>
        <shape>
            <padding android:top="0dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke
                android:width="1dp"
                android:color="#ffe1e1e1" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item>
        <shape>
            <padding android:top="0dp" android:right="0dp" android:bottom="1dp" android:left="0dp" />
            <stroke
                android:width="1dp"
                android:color="#ffdbdbdb" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <item>
        <shape>
            <padding android:top="0dp" android:right="0dp" android:bottom="1dp" android:left="0dp" />
            <stroke
                android:width="1dp"
                android:color="#ffd5d5d5" />
            <corners android:radius="2dp" />
        </shape>
    </item>

    <!--
    <item>
        <shape>
            <padding android:top="0dp" android:right="0dp" android:bottom="1dp" android:left="0dp" />
            <stroke
                android:width="1dp"
                android:color="#ffcfcfcf" />
            <corners android:radius="2dp" />
        </shape>
    </item>
    -->

    <item>
        <shape>
            <solid android:color="#ffffe1b3" />
            <stroke
                android:width="1px"
                android:color="#fff76d3c" />
            <corners android:radius="2dp" />
        </shape>
    </item>
</layer-list>

statelist_item_background.xml

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

    <item android:state_pressed="true" android:drawable="@drawable/card_selected" />     <!-- pressed -->
    <item android:state_selected="true" android:drawable="@drawable/card_selected" />     <!-- pressed -->

    <item android:drawable="@drawable/card" />

</selector>

layout.xml

<!-- A CardView that contains a TextView -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:padding="10dp"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="5dp"
    android:layout_marginBottom="5dp"
    android:background="@drawable/statelist_item_background"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true" >

    <TextView
        android:id="@+id/txt_label_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        tools:text="Item Number One" />

    <TextView
        android:id="@+id/txt_date_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        tools:text="Item Number One" />
</LinearLayout>

You will get the pretty nice outcome.

enter image description here

like image 111
Cheok Yan Cheng Avatar answered Oct 22 '25 00:10

Cheok Yan Cheng


I've just tried MaterialCardView and this works:

<com.google.android.material.card.MaterialCardView
    android:id="@+id/material_card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/activity_vertical_margin"
    app:cardCornerRadius="4dp"
    app:cardBackgroundColor="@color/selector_background_color"
    app:strokeWidth="2dp">

selector_background_color.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/white" android:state_activated="true"/>
<item android:color="@android:color/darker_gray" android:state_activated="false"/>

In the Activity/Fragment:

material_card_view.setOnClickListener {
        it.isActivated = !it.isActivated
}

For the strokeColor though, you can't use a selector. You will have to do it programmatically if you want the stroke color to change as per selector state.

Example for state_activated:

val colorStateList: ColorStateList = 
ResourcesCompat.getColorStateList(resources, 
R.color.selector_stroke_color, null)!!
val colorForState =colorStateList.getColorForState(intArrayOf(android.R.attr.state_activated), colorStateList.defaultColor)
material_card_view.strokeColor = colorForState
like image 30
ExpensiveBelly Avatar answered Oct 21 '25 23:10

ExpensiveBelly