Effet d'entraînement sur Android Lollipop CardView

192

J'essaie d'obtenir un CardView pour afficher l'effet d'entraînement lorsqu'il est touché en définissant l'attribut android: backgound dans le fichier XML d'activité comme décrit ici sur la page Développeurs Android, mais cela ne fonctionne pas. Aucune animation, mais la méthode dans onClick est appelée. J'ai également essayé de créer un fichier ripple.xml comme suggéré ici , mais le même résultat.

Le CardView tel qu'il apparaît dans le fichier XML de l'activité:

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

Je suis relativement nouveau dans le développement Android, donc j'ai peut-être fait quelques erreurs évidentes.

AkraticCritic
la source

Réponses:

594

Vous devez ajouter ce qui suit à CardView:

android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
Jaden Gu
la source
8
Fonctionne sur sucette avec effet d'entraînement mais ne donne une couleur unie que lorsqu'elle est exécutée sur des plates-formes plus anciennes. Assez bien pour moi :)
mach
16
Un petit constat: j'ai noté que l'attribut cliquable n'est pas nécessaire et peut même casser certaines choses! J'avais un GridView rempli de CardViews cliquables et l'auditeur ne fonctionnait pas correctement. J'ai supprimé la balise cliquable du XML et tout fonctionne maintenant parfaitement
Joaquin Iurchuk
2
@joaquin sans le cliquable, cela fait que l'ondulation provient du centre uniquement
frostymarvelous
2
?android:attr/selectableItemBackgroundnécessite le niveau d'API 11
Pratik Butani
9
Travailler sans android:clickable="true".
Sean
30

Ajoutez ces deux codes de ligne dans votre vue xml pour donner un effet d'entraînement sur votre cardView.

android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
Abdul Rizwan
la source
Impressionnant! foregroundfonctionne avec des vues d'arrière-plan personnalisées comme un charme! Agréable!
sud007
24

J'ai réussi à obtenir l'effet d'entraînement sur la vue de la carte en:

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

et pour le custom_bg que vous pouvez voir dans le code ci-dessus, vous devez définir un fichier xml pour les périphériques lollipop (dans le package drawable-v21) et pré-lollipop (dans le package drawable). pour custom_bg dans le package drawable-v21, le code est:

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

pour custom_bg dans le package drawable, le code est:

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

Ainsi, sur les appareils pré-lollipop, vous aurez un effet de clic solide et sur les appareils sucette, vous aurez un effet d'entraînement sur la vue de la carte.

Rahul Ahuja
la source
1
Salut, je me rends compte qu'en appliquant le sélecteur (ou ondulation) au premier plan de CardView, il bloquera les enfants dans CardView lui-même - stackoverflow.com/questions/33763403/ ... Puis-je savoir que vous rencontrez le même problème que moi? Ou est-ce que je rate quelque chose? Merci.
Cheok Yan Cheng
@CheokYanCheng: Je ne suis pas confronté à un problème tel que le vôtre, mais je dirais par expérience personnelle que cardView a quelques bugs pour pré-sucette. Évitez d'utiliser cardview: propriété d'élévation dans pré-sucette. Ce qui précède fonctionne bien pour moi et pour d'autres votes positifs.
Rahul Ahuja
Puis-je savoir quelle est la valeur de votre colorHighlight & navigation_drawer_background. Si vous avez utilisé votre propre couleur définie sans transparence, pouvez-vous toujours voir les enfants de votre carte?
Cheok Yan Cheng
@CheokYanCheng: les valeurs sont comme, <color name = "navigation_drawer_background"> ​​# FFFFFF </color> <color name = "colorHighlight"> # FF8A65 </color>
Rahul Ahuja
Je ne travaille pas pour mon cas. J'utilise votre sélecteur comme premier plan. Comme prévu, la couleur blanche unie (navigation_drawer_background), qui est utilisée comme vue de la carte au premier plan, bloquera la visibilité de tous les enfants - i.imgur.com/CleYh5B.png Voici à quoi cela ressemble sans appliquer le sélecteur au premier plan - i.imgur. com / ZXk5Aoq.png
Cheok Yan Cheng
14

L'effet d'entraînement a été omis dans la bibliothèque de support appcompat qui est ce que vous utilisez. Si vous voulez voir l'ondulation, utilisez la version Android L et testez-la sur un appareil Android L. Sur le site AppCompat v7:

"Pourquoi n'y a-t-il pas d'ondulations sur les versions antérieures à Lollipop? Le nouveau RenderThread d'Android 5.0 est en grande partie ce qui permet à RippleDrawable de fonctionner correctement. Pour optimiser les performances des versions précédentes d'Android, nous avons laissé RippleDrawable pour le moment."

Consultez ce lien ici pour plus d'informations

Développeur Paul
la source
Ce serait tout. Merci!
AkraticCritic
39
Mais comment mettriez-vous l'effet d'entraînement sur cardView pour Android Lollipop alors?
développeur android
Je dois donc choisir entre la compatibilité descendante en utilisant appcompat ou avoir tous les nouveaux effets, en utilisant les classes du noyau Android mais en me limitant à l'API 21?
Urs Reupke
Vous pouvez créer 2 APK pour 21+ et l'autre pour <21. Ou diviser le code puisque 21+ n'utiliseront pas supportActionbar etc. Cela peut sembler beaucoup de problèmes, mais c'est votre solution je crois.
Mathijs Segers
1
C'est pourquoi écrire des applications Android L "pures" n'est pas viable pour le moment. À partir de juillet 2015, vous ciblerez 12% de la base d'utilisateurs Android.
Glenn Bech
10

Si l'application sur minSdkVersionlaquelle vous travaillez est de niveau 9, vous pouvez utiliser:

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

Au lieu de cela, à partir du niveau 11, vous utilisez:

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

De la documentation:

cliquable - Définit si cette vue réagit aux événements de clic. Doit être une valeur booléenne, "true" ou "false".

premier plan - Définit le dessin à dessiner sur le contenu. Cela peut être utilisé comme superposition. Le dessinable de premier plan participe au remplissage du contenu si la gravité est définie pour remplir.

Filipe Brito
la source
En utilisant android: foreground = "? Android: attr / selectableItemBackground" a fonctionné pour la compatibilité AndroidX, merci!
dianakarenms le
6

Pour moi, l'ajout de foregroundà CardViewn'a pas fonctionné (raison inconnue: /)

L'ajout de la même chose à sa disposition enfant a fait l'affaire.

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>
Prabes
la source
2
C'est parce que l'enfant intercepte l'événement, si vous essayez quelque chose comme ajouter un remplissage à la vue de la carte (quelque chose comme 20dp), et que vous cliquez sur la partie où le remplissage serait, alors vous verrez l'effet d'entraînement même sans que l'enfant ait l'ensemble d'attributs de premier plan
Cruces
1
Cela a également fonctionné pour moi, en utilisant les nouveaux composants matériels: com.google.android.material.card.MaterialCardView. J'avais un stateListAnimator d'élévation pour la vue de carte pour ajuster l'élévation et l'ondulation appliquée à la disposition de contrainte interne avec l'arrière-plan de l'élément sélectionnable au premier plan sans attribut cliquable.
Patty P
Je ne m'en souviens pas maintenant, mais il existe un moyen de définir les vues enfants pour qu'elles ne réagissent pas à l'événement de clic
Someone Somewhere
3

Ajoutez ces deux types de code fonctionnent comme un charme pour n'importe quelle vue comme Button, Linear Layout ou CardView.Il suffit de mettre ces deux lignes et de voir la magie ...

android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
Hitesh Kushwah
la source
2

S'il existe une disposition racine telle que RelativeLayout ou LinearLayout qui contient tous les composants de l'élément adaptateur dans CardView, vous devez définir l'attribut d'arrière-plan dans cette disposition racine. comme:

<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>
Robert Lee
la source
2

Événement Ripple pour le Cardviewcontrôle Android :

<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" />
chavanNil
la source
1

Je n'étais pas satisfait d'AppCompat, j'ai donc écrit mon propre CardView et des ondulations rétroportées. Ici, il fonctionne sur Galaxy S avec Gingerbread, donc c'est certainement possible.

Démo de Ripple sur Galaxy S

Pour plus de détails, vérifiez le code source .

Zielony
la source
le lien est rompu
temirbek
1

Ajoutez ce qui suit à votre xml:

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

Et ajoutez à votre adaptateur (si c'est votre cas)

    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)
        }
    }
Mateus Melo
la source
0

Pour ceux qui recherchent une solution au problème de l'effet d'entraînement ne fonctionnant pas sur un CardView créé par programme (ou dans mon cas une vue personnalisée qui étend CardView) affiché dans un RecyclerView, ce qui suit a fonctionné pour moi. En gros, déclarer les attributs XML mentionnés dans les autres réponses de manière déclarative dans le fichier de mise en page XML ne semble pas fonctionner pour un CardView créé par programme, ou créé à partir d'une mise en page personnalisée (même si la vue racine est CardView ou si un élément de fusion est utilisé), donc ils doivent être définis par programme comme ceci:

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 CardViewBravo à cette réponse pour la TypedArraypartie.

Breeno
la source
0
  android:foreground="?android:attr/selectableItemBackgroundBorderless"
   android:clickable="true"
   android:focusable="true"

Ne fonctionne que l'API 21 et ne l'utilise pas utilise cette vue de carte de ligne de liste

Tarun Umath
la source
0

Utilisez à la place Material Cardview, il étend Cardview et fournit plusieurs nouvelles fonctionnalités, y compris l'effet cliquable par défaut:

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

...

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

Dépendance

implementation 'com.google.android.material:material:1.0.0'
Ankit
la source