I'm trying to get a CardView to display the ripple effect when touched by setting the android:backgound attribute in the activity XML file as described here on the Android Developers page, but it isn't working. No animation at all, but the method in onClick is called. I've also tried creating a ripple.xml file as suggested here, but same result.
The CardView as it appears in the activity's XML file:
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="155dp"
android:layout_height="230dp"
android:elevation="4dp"
android:translationZ="5dp"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:onClick="showNotices"
android:background="?android:attr/selectableItemBackground"
android:id="@+id/notices_card"
card_view:cardCornerRadius="2dp">
</android.support.v7.widget.CardView>
I'm relatively new to android development, so I might have made a few obvious mistakes.
This question is related to
android
android-layout
android-5.0-lollipop
android-cardview
For those searching for a solution to the issue of the ripple effect not working on a programmatically created CardView (or in my case custom view which extends CardView) being shown in a RecyclerView, the following worked for me. Basically declaring the XML attributes mentioned in the other answers declaratively in the XML layout file doesn't seem to work for a programmatically created CardView, or one created from a custom layout (even if root view is CardView or merge element is used), so they have to be set programmatically like so:
private class MadeUpCardViewHolder extends RecyclerView.ViewHolder {
private MadeUpCardView cardView;
public MadeUpCardViewHolder(View v){
super(v);
this.cardView = (MadeUpCardView)v;
// Declaring in XML Layout doesn't seem to work in RecyclerViews
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int[] attrs = new int[]{R.attr.selectableItemBackground};
TypedArray typedArray = context.obtainStyledAttributes(attrs);
int selectableItemBackground = typedArray.getResourceId(0, 0);
typedArray.recycle();
this.cardView.setForeground(context.getDrawable(selectableItemBackground));
this.cardView.setClickable(true);
}
}
}
Where MadeupCardView extends CardView
Kudos to this answer for the TypedArray
part.
I wasn't happy with AppCompat, so I wrote my own CardView and backported ripples. Here it's running on Galaxy S with Gingerbread, so it's definitely possible.
For more details check the source code.
I managed to get the ripple effect on the cardview by :
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:clickable="true"
android:foreground="@drawable/custom_bg"/>
and for the custom_bg that you can see in above code, you have to define a xml file for both lollipop(in drawable-v21 package) and pre-lollipop(in drawable package) devices. for custom_bg in drawable-v21 package the code is:
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item
android:id="@android:id/mask"
android:drawable="@android:color/white"/>
</ripple>
for custom_bg in the drawable package, code is:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="@color/colorHighlight"></solid>
</shape>
</item>
<item>
<shape>
<solid android:color="@color/navigation_drawer_background"></solid>
</shape>
</item>
</selector>
so on pre-lollipop devices you will have a solid click effect and on lollipop devices you will have a ripple effect on the cardview.
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
Only working api 21 and use this not use this list row card view
If there is a root layout like RelativeLayout or LinearLayout which contain all of the adapter item's component in CardView, you have to set background attribute in that root layout. like:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="122dp"
android:layout_marginBottom="6dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
card_view:cardCornerRadius="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/touch_bg"/>
</android.support.v7.widget.CardView>
Add these two line code into your xml view to give ripple effect on your cardView.
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
Add these two like of code work like a charm for any view like Button, Linear Layout, or CardView Just put these two lines and see the magic...
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
If the app minSdkVersion
which you are working is level 9, you can use:
android:foreground="?selectableItemBackground"
android:clickable="true"
Instead, starting from level 11, you use:
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
From documentation:
clickable - Defines whether this view reacts to click events. Must be a boolean value, either "true" or "false".
foreground - Defines the drawable to draw over the content. This can be used as an overlay. The foreground drawable participates in the padding of the content if the gravity is set to fill.
Use Material Cardview instead, it extends Cardview and provides multiple new features including default clickable effect :
<com.google.android.material.card.MaterialCardView>
...
</com.google.android.material.card.MaterialCardView>
Dependency (It can be used up to API 14 to support older device):
implementation 'com.google.android.material:material:1.0.0'
For me, adding the foreground
to CardView
didn't work (reason unknown :/)
Adding the same to it's child layout did the trick.
CODE:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="true"
android:clickable="true"
card_view:cardCornerRadius="@dimen/card_corner_radius"
card_view:cardUseCompatPadding="true">
<LinearLayout
android:id="@+id/card_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
android:padding="@dimen/card_padding">
</LinearLayout>
</android.support.v7.widget.CardView>
The ripple effect was omitted in the appcompat support library which is what you're using. If you want to see the ripple use the Android L version and test it on an Android L device. Per the AppCompat v7 site:
"Why are there no ripples on pre-Lollipop? A lot of what allows RippleDrawable to run smoothly is Android 5.0’s new RenderThread. To optimize for performance on previous versions of Android, we've left RippleDrawable out for now."
Check out this link here for more info
Ripple event for android Cardview
control:
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp" />
Add the following to your xml:
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
And add to your adapter (if it's your case)
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val attrs = intArrayOf(R.attr.selectableItemBackground)
val typedArray = holder.itemView.context.obtainStyledAttributes(attrs)
val selectableItemBackground = typedArray.getResourceId(0, 0)
typedArray.recycle()
holder.itemView.isClickable = true
holder.itemView.isFocusable = true
holder.itemView.foreground = holder.itemView.context.getDrawable(selectableItemBackground)
}
}
Source: Stackoverflow.com