web-dev-qa-db-fra.com

Sélecteur Listview avec arrière-plan coloré et effet d'entraînement

Standard ListView sélecteur dans Android) L'aperçu du développeur utilise colorControlHighlight pour l'effet d'entraînement au toucher et possède un arrière-plan transparent à l'état flou.

Je voudrais définir un élément ListView qui a un arrière-plan coloré et qui montre toujours l’effet d’ondulation au toucher avec la même couleur de surbrillance. Maintenant, si je définis le drawable suivant:

<ripple xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:color="?android:colorControlHighlight">
    <item Android:drawable="@color/my_background_color"/>
</ripple>

cela fonctionne, mais l'ondulation commence au milieu de l'élément ListView, quelle que soit la position de contact. Si j'utilise le même fond en dehors de ListView, par exemple. pour un LinearLayout, cela fonctionne comme prévu (l'ondulation commence à la position tactile).

55
artkoenig

J'ai réussi à obtenir des éléments de liste colorés individuellement tout en maintenant l'effet d'entraînement. Définissez l’arrière-plan de vos éléments de liste à l’aide de l’adaptateur que vous possédez et réglez la liste pour afficher le sélecteur en haut:

<ListView
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:drawSelectorOnTop="true" />

Cela dessinera l'effet d'entraînement au-dessus de l'arrière-plan.

126
dyancat

Autant que je sache, ce bogue n'apparaît que dans Android 5.0, et non 5.1. L'astuce semble consister à utiliser Drawable # setHotspot en tant qu'indicateur de développement Google ici https://Twitter.com/crafty/status/561768446149410816 (car des astuces obscures sur Twitter sont une excellente forme de documentation!)

Supposons que vous avez une disposition en ligne quelque chose comme ça

<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

      <LinearLayout
            Android:id="@+id/row_content"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:orientation="horizontal"
            Android:background="?attr/selectableItemBackground">

          .... content here .....

     </LinearLayout>

</FrameLayout>

Ce qui suit a fonctionné pour moi

            row.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    v.findViewById(R.id.row_content)
                        .getBackground()
                        .setHotspot(event.getX(), event.getY());

                    return(false);
                }
            });
6
miguel

j'ai adapté un peu la réponse de @ArhatBaid, je l'ai testée et elle fonctionne parfaitement:

<ripple xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:color="?android:colorControlHighlight">
    <item Android:drawable="@color/light_grey_header_navigation_drawer"/>
</ripple>

Cela vous permet donc de définir une couleur d’arrière-plan tout en conservant l’effet d’ondulation.
pour moi, cible et minSdk ont ​​21 ans.

3
cV2

L'exemple de disposition, qui contient l'effet Ripple en tant qu'arrière-plan de la disposition parente.

<RelativeLayout 
                Android:id="@+id/id4"
                Android:layout_width="fill_parent"
                Android:layout_height="wrap_content"
                Android:background="@drawable/ripple_effect"
                Android:clickable="true">

                <ImageView 
                    Android:id="@+id/id3"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    Android:layout_alignParentLeft="true"
                    Android:background="@drawable/image"
                    Android:layout_centerVertical="true"/>

                <LinearLayout
                    Android:id="@+id/id2" 
                    Android:layout_width="fill_parent"
                    Android:layout_height="wrap_content"
                    Android:orientation="vertical"
                    Android:layout_alignParentRight="true"
                    Android:layout_centerVertical="true">

                    <TextView 
                        Android:id="@+id/id1"
                        Android:layout_width="wrap_content"
                        Android:layout_height="wrap_content"
                        Android:text="@string/text"/>

                </LinearLayout>
            </RelativeLayout>

Ripple_effect.xml Ici, vous pouvez utiliser n’importe quelle couleur de votre choix. Assurez-vous d’utiliser sdk version 21 et d’avoir les dossiers drawable-v21 et style-v21 et de placer tous les fichiers associés à la v21.

<ripple xmlns:Android="http://schemas.Android.com/apk/res/Android" 
                  Android:color="?android:colorControlHighlight">
    <item Android:id="@Android:id/mask">
        <shape Android:shape="oval">
            <solid Android:color="?android:colorAccent" />
        </shape>
    </item>

Ici, vous pouvez utiliser une forme différente comme un rectangle au lieu d'un ovale ...

3
Arhat Baid

J'ai constaté que cela ne semble fonctionner correctement que si vous appliquez l'arrière-plan à l'élément racine de l'élément de liste.

En outre, envisagez d’utiliser le nouveau RecyclerView au lieu d’un ListView.

Exemple de vue d'élément de liste:

<RelativeLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:layout_marginTop="@dimen/list_padding"
    Android:layout_marginLeft="@dimen/list_padding"
    Android:layout_marginRight="@dimen/list_padding"
    Android:padding="@dimen/list_padding"
    Android:background="@drawable/ripple_bg">

    <TextView
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="Large Text"
        Android:id="@+id/tvTitle"/>

    <TextView
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="Small Text"
        Android:id="@+id/tvSubtitle" />

</RelativeLayout>
3
JoeyCK

Vous pouvez y parvenir avec une mise en page imbriquée. Il suffit de créer par exemple un LinearLayout en tant que mise en page racine autour de votre mise en page existante, définissez l'effet d'entraînement sur la mise en page racine et votre couleur d'arrière-plan sur celle imbriquée.

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="@drawable/ripple_effect"
    Android:orientation="vertical">

    <RelativeLayout xmlns:app="http://schemas.Android.com/apk/res-auto"
        Android:id="@+id/containterContent"
        Android:background="@color/yourCOLOR"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent">

        <!-- Your content -->

    </RelativeLayout>
</LinearLayout>
2
Sascha