24

Has anybody solved the mystery of the CardView without touch feedback when it's inside a RecyclerView?

I have a RecyclerView with a bunch of CardViews (a CardList). When I click on any CardView, I start another Activity. That's working pretty fine, but I can't see any touch feedback when I click on the CardView.

Just in time, I've already configured my CardView (XML) with these:

android:clickable="true"
android:background="?android:selectableItemBackground"

Thanks!

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
Rafael Nascimento
  • 715
  • 2
  • 8
  • 19
  • Does this answer your question? [Android-L CardView Visual Touch Feedback](https://stackoverflow.com/questions/24475150/android-l-cardview-visual-touch-feedback) – childno͡.de Mar 18 '21 at 20:40

5 Answers5

41

Background:

The CardView ignores android:background in favor of app:cardBackground which can only be color. The border and shadow are in fact part of the background so you cannot set your own.

Solution:

Make the layout inside the CardView clickable instead of the card itself. You already wrote both attributes needed for this layout:

android:clickable="true"
android:background="?android:selectableItemBackground"
Eugen Pechanec
  • 37,669
  • 7
  • 103
  • 124
  • 1
    Hey! Sorry! You were right. What was cheating me is that I'm using the Theme.Material theme, and it's a "dark" theme. Since I've changed to Theme.Material.Light, and used your answer, the touch feedback took place. – Rafael Nascimento Jan 04 '15 at 02:45
  • This works okay in Lollipop and above. On Kit Kat the background of the inner view does not cover the whole cardView (here is where you realize the shadows are fake in Kit Kat). It's okay but not perfect. I can live with it for now. – Sotti Mar 12 '15 at 15:48
  • Yes, I think I had the same problem. I don't remember how I solved it but setting `contentPadding` on the card to the same value as negative `cardCornerRadius` (to be precise the root value of it i think) should do half the job (make sure to set `useCompatPadding` to `true`). The second half is creating a custom background `` STATEFUL! drawable with the same corner size. The third half is defining a drawable-v21 which uses ripples instead. I'll try to update the answer with a sample later. – Eugen Pechanec Mar 12 '15 at 16:00
  • 6
    `android:foreground="?android:selectableItemBackground"` on `CardView` was a cleaner solution for me since making the layout inside `CardView` clickable was disabling my the item click listener – Carlo Espino Apr 01 '16 at 08:47
8

Solution 1

As @Eugen proposed, you can make the layout inside CardView clickable, so then you can use android:background:

<android.support.v7.widget.CardView
    ...
    android:clickable="true"
    android:background="?attr/selectableItemBackground">

Solution 2

If you don't want to lose the item click listener by making the layout inside CardView clickable, you can use android:foreground:

<android.support.v7.widget.CardView
    ...
    android:clickable="true"
    android:foreground="?attr/selectableItemBackground">

Extra: you can use "?attr/selectableItemBackgroundBorderless" instead of "?attr/selectableItemBackground" if you don't want the rectangle mask.

Joonsoo
  • 788
  • 1
  • 13
  • 15
David Miguel
  • 12,154
  • 3
  • 66
  • 68
  • foreground for the CardView is the only solution that worked with me. Thank you. – Mohamed Nageh Feb 07 '19 at 12:34
  • This code sample is confusing - there's no layout in the CardView. What's the point of borderless selector if it's already clipped by the card shape? It looks the same. – Eugen Pechanec Mar 09 '19 at 10:58
1

create selector "drawable/card_foreground_selector"

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#18000000"/>
            <corners android:radius="@dimen/card_radius" />
        </shape>
    </item>
    <item android:state_focused="true" android:state_enabled="true">
        <shape android:shape="rectangle">
            <solid android:color="#0f000000"/>
            <corners android:radius="@dimen/card_radius" />
        </shape>
    </item>
</selector>

and create "drawable/card_foreground.xml" (you'll need to tweak inset values according to elevation of your card)

<inset xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/card_foreground_selector"
android:insetLeft="2dp"
android:insetRight="2dp"
android:insetTop="3dp"
android:insetBottom="3dp"/>

modify your item (item.xml)

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:contentPadding="8dp"
    android:foreground="@drawable/card_foreground">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    // ..

    </LinearLayout>
</android.support.v7.widget.CardView>

you can view original post here

Community
  • 1
  • 1
Gilang
  • 11
  • 1
  • 2
    Instead of creating a new drawable I just used `android:foreground="?android:selectableItemBackground"` – Carlo Espino Apr 01 '16 at 08:34
  • @CarloRodríguez That's "?selectableItemBackground" for AppCompat. Does it work on all platforms? The custom drawable is used before Lollipop because the corners on ?selectableItemBackground aren't clipped. – Eugen Pechanec Apr 01 '16 at 17:44
  • @EugenPechanec you're right, I didn't realize the corners aren't clipped before Lollipop, it may be still a good option if card view has no corner radius. – Carlo Espino Apr 01 '16 at 19:39
1

Add foreground attribute:

android:foreground="?android:attr/selectableItemBackground"
Volodymyr Kulyk
  • 6,455
  • 3
  • 36
  • 63
1

Both Approach should work the same way.

1) If you want cardview to respond to touch feedback then use this one in cardview.

 android:foreground="?android:attr/selectableItemBackground"
        android:clickable="true"
        android:focusable="true"

but if above approach is not working then you can set this property on child view group (Linear/Relative etc) of cardview.

   android:background="?android:attr/selectableItemBackground"
    android:clickable="true"
    android:focusable="true"

But then itemView of ViewHolder will not respond to the touch event. since its been consumed by child view so you have to set clicklistener on childview to work on further with listener in recyclerview adapter, this way we can enable touch as well as click events on row items of recyclerview in our adapter.

if you have hard time following the touch and click on views in cardview with ripple then this might be helpful. Touch Feedback Problem

2.) The second approach is to use the traditional way of using custom touch selector drawable and set as background.

    <?xml version="1.0" encoding="utf-8"?>
<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="your ripple color">
    <item>
    <selector>
        <item android:state_selected="true">
            <color android:color="your selected color" />
        </item>
        <item android:state_activated="true">
            <color android:color="your selected color" />
        </item>
        <item>
            <color android:color="your normal color" />
        </item>
    </selector>
    </item>
</ripple>

Docs Ripple Drawable

Community
  • 1
  • 1
vikas kumar
  • 10,447
  • 2
  • 46
  • 52