Android Lollipop CardView的涟漪效应

248

我正在尝试通过在活动的XML文件中设置android:background属性来显示CardView触摸时的涟漪效果,如Android开发者页面上这里所述,但它不起作用。没有任何动画,但是onClick方法被调用了。我也尝试像这里建议的创建一个ripple.xml文件,但结果相同。

这是活动的XML文件中CardView的外观:

<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> 

我对Android开发还比较新,所以可能会犯一些明显的错误。

14个回答

740

你应该将以下内容添加到CardView中:

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

10
在棒棒糖系统中使用具有涟漪效果,但在旧平台上运行时仅提供单色。对我来说已经足够好了 :) - mach
21
一点观察:我注意到clickable属性是不必要的,甚至可能会导致一些问题!我有一个包含可点击CardViews的GridView,但监听器没有正常工作。我从XML中删除了clickable标记,现在一切都完美地运行了。 - Joaquin Iurchuk
2
"?android:attr/selectableItemBackground" 需要 API 级别 11。 - Pratik Butani
13
و²،وœ‰ن½؟用android:clickable="true"çڑ„ه·¥ن½œو–¹ه¼ڈم€‚ - Sean
11
为了更好地使用CardView,建议使用?attr/selectableItemBackgroundBorderless - Danylo.Vus
显示剩余18条评论

32

我通过以下方式在卡片视图上实现了涟漪效果:

<android.support.v7.widget.CardView 
    xmlns:card_view="http://schemas.android.com/apk/res-auto" 
    android:clickable="true" 
    android:foreground="@drawable/custom_bg"/>

而对于上面代码中可以看到的custom_bg,您需要为Lollipop(在drawable-v21包中)和Pre-Lollipop(在drawable包中)设备分别定义一个xml文件。

对于drawable-v21包中的custom_bg代码如下:

<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>

对于drawable包中的custom_bg,代码如下:

<?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>

在安卓5.0以下的设备上,你会看到CardView有一个实心的点击效果;而在安卓5.0及以上的设备上,你会看到CardView有一个涟漪效果。


2
嗨,我发现通过在CardView的前景上应用选择器(或涟漪效果),它会阻止CardView本身中的子元素 - https://dev59.com/0ZHea4cB1Zd3GeqPli3l 请问您是否遇到了与我相同的问题?或者,我有什么遗漏吗?谢谢。 - Cheok Yan Cheng
@CheokYanCheng :我没有像你那样遇到这个问题,但从个人经验来看,卡片视图在早期的安卓版本中存在一些错误。建议在早期安卓版本中避免使用cardView:elevation属性。以上对我和其他点赞用户都有效。 - Rahul Ahuja
我不适用我的情况。我使用您的选择器作为前景。正如预期的那样,纯白色(navigation_drawer_background)被用作卡片视图前景,将阻挡所有子元素的可见性 - http://i.imgur.com/CleYh5B.png 这是没有将选择器应用为前景时的外观 - http://i.imgur.com/ZXk5Aoq.png - Cheok Yan Cheng
你创建了正确的包吗?如上所述.. @CheokYanCheng - Rahul Ahuja
你需要预设卡片视图的高度并将match_parent设置在内部。 - Jeff Bootsholz
显示剩余2条评论

15
如果你所使用的应用程序的minSdkVersion是9级,你可以使用:
android:foreground="?selectableItemBackground"
android:clickable="true"

相反,从第11级开始,您将使用:

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

来自文档:

clickable - 定义此视图是否对点击事件做出反应。必须是布尔值,可以是“true”或“false”。

foreground - 定义要绘制在内容上方的可绘制对象。这可用作叠加层。如果重力设置为填充,则前景可绘制对象参与内容的填充。


使用android:foreground="?android:attr/selectableItemBackground" 可以实现AndroidX兼容性,谢谢! - dianakarenms

15

应用程序兼容支持库中省略了波纹效果,这就是您正在使用的库。如果您想查看涟漪效果,请使用Android L版本并在Android L设备上测试。根据AppCompat v7网站:

"为什么在Lollipop之前没有涟漪效果? 许多使RippleDrawable平稳运行的因素是Android 5.0的新RenderThread。为了优化先前的Android版本的性能,我们暂时省略了RippleDrawable。"

请查看此链接这里以获取更多信息


就这样了。谢谢! - AkraticCritic
40
那么,你如何将涟漪效果应用到Android Lollipop上的卡片视图中呢? - android developer
所以我必须在使用appcompat保持向后兼容性和使用来自Android核心的类实现所有新特效之间做出决定,但这将限制我只能使用API 21。 - Urs Reupke
你可以制作两个APK,一个针对21岁以上的用户,另一个针对21岁以下的用户。或者将代码分开,因为21岁以上的用户不会使用supportActionbar等功能。这可能听起来很麻烦,但我认为这是你的解决方案。 - Mathijs Segers
1
这就是为什么目前编写“纯”Android L应用程序不可行的原因。截至2015年7月,您将面向Android用户群体的12%。 - Glenn Bech

13

使用Material CardView代替,它扩展了CardView并提供了多个新功能,包括默认的可点击效果:

<com.google.android.material.card.MaterialCardView>

...

</com.google.android.material.card.MaterialCardView>

依赖项 (它可以在API 14及以下版本中使用,以支持旧设备):

implementation 'com.google.android.material:material:1.0.0'

1
你是对的。不要忘记添加 android:clickable="true" 和 android:focusable="true"。 - Burak Dizlek
@BurakDizlek 为什么我们需要 clickablefocusable 属性?当使用 <com.google.android.material.card.MaterialCardView> 时,我看不到任何区别。 - Andy
1
@andy 我猜,如果你已经在你的卡片上设置了setonclicklistener,那么它是不需要的,否则如果你想要水波纹效果而没有设置setonclicklistener,那么就在你的xml中添加它。 - Ankit Gupta

7

对我来说,在CardView中添加foreground没有起作用(原因未知 :/)

但是在它的子布局中添加相同的代码就可以解决问题。

代码:

<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>

2
这是因为子元素拦截了事件。如果您尝试像添加卡片视图(例如20dp)的填充那样的操作,并单击填充位置,那么即使子元素没有设置前景属性,您也会看到涟漪效果。 - Cruces
1
这对我也起了作用,使用了新的Material Components:com.google.android.material.card.MaterialCardView。我为卡片视图设置了一个高度状态列表动画来调整高度,并将涟漪应用于具有可选择项目前景背景而没有可点击属性的内部约束布局。 - Patty P
我现在记不清了,但有一种方法可以设置子视图不响应点击事件。 - Someone Somewhere

7

加入以下两行代码,就能让任何视图像按钮(Button),线性布局(Linear Layout)或卡片视图(CardView)一样完美显示。只需加入这两行代码,即可见识奇妙的效果...

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

3
将以下内容添加到您的xml中:
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"

并将以下内容添加到您的适配器中(如果适用)。
    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)
        }
    }

2

对于那些在RecyclerView中显示编程创建的CardView(或我这种情况下扩展了CardView的自定义视图)时遇到波纹效果无法正常工作的问题,以下内容对我有效。基本上,在XML布局文件中声明其他答案中提到的XML属性似乎对于编程创建的CardView或从自定义布局创建的CardView(即使根视图为CardView或使用合并元素)无效,因此必须像下面一样通过编程方式设置:

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);
        }
    }
}

在这里,MadeupCardView extends CardView,感谢这个回答提供的TypedArray部分。


1
感谢您的回答。在我的情况下,我通过编程将 clickable 和 focusable 设置为 true,使其开始在我的自定义视图上显示水波纹效果(视图的父级是 MaterialCardView)。 - intips

2

Ripple事件适用于Android Cardview控件:

<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" />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接