Comment définir l'effet de clic de bouton dans Android?

105

Sous Android, lorsque je définis l'image d'arrière-plan sur Button, je ne vois aucun effet sur le bouton.

J'ai besoin d'un effet sur le bouton pour que l'utilisateur puisse reconnaître que le bouton a été cliqué.

Le bouton doit être sombre pendant quelques secondes lorsqu'il a cliqué, alors que dois-je faire pour cela?

Merci.

Jignesh Ansodariya
la source
La méthode suivante vous permet d'utiliser une seule
classe de style pour habiller
non je n'utilise pas le bouton image, j'utilise le bouton normal de manière simple pour cela?
Jignesh Ansodariya
3
Son très beau tutoriel: dibbus.com/2011/02/gradient-buttons-for-android
Pratik Butani

Réponses:

154

Cela peut être réalisé en créant un fichier xml dessinable contenant une liste d'états pour le bouton. Par exemple, si vous créez un nouveau fichier xml appelé "button.xml" avec le code suivant:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/YOURIMAGE" />
    <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/gradient" />
    <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/gradient" />
    <item android:drawable="@drawable/YOURIMAGE" />
</selector>

Pour conserver l'image d'arrière-plan avec une apparence sombre sur presse, créez un deuxième fichier xml et appelez-le gradient.xml avec le code suivant:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <bitmap android:src="@drawable/YOURIMAGE"/>
    </item>
    <item>
        <shape xmlns:android="http://schemas.android.com/apk/res/android">
            <gradient android:angle="90" android:startColor="#880f0f10" android:centerColor="#880d0d0f" android:endColor="#885d5d5e"/>
        </shape>
    </item>
</layer-list>

Dans le xml de votre bouton, définissez l'arrière-plan comme le bouton xml par exemple

android:background="@drawable/button"

J'espère que cela t'aides!

Modifier: le code ci-dessus a été modifié pour afficher une image (VOTRE IMAGE) dans le bouton par opposition à une couleur de bloc.

Ljdawson
la source
Alors, où puis-je définir l'image pour l'arrière-plan du bouton, pour définir l'image est le must
Jignesh Ansodariya
1
Édité pour montrer comment utiliser une image d'arrière-plan avec l'état XML. Remplacez YOURIMAGE par la ressource image dans votre répertoire dessinable.
Ljdawson
Cela ne fonctionne que si le src du bouton est rectangulaire. Si le dessinable src a une forme différente de celle-ci, le dégradé sera également appliqué à l'arrière-plan, et c'est triste.
Renato Lochetti
Pas vraiment, pourrait toujours utiliser une forme différente dans la liste des
calques
2
pendant que j'utilise une image, cela fonctionne pour moi .. mais quand j'utilise un arrière-plan Xml. ça ne marche pas ...
DKV
88

C'est plus simple quand vous avez beaucoup de boutons d'image et que vous ne voulez pas écrire xml-s pour chaque bouton.

Version Kotlin:

fun buttonEffect(button: View) {
    button.setOnTouchListener { v, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                v.background.setColorFilter(-0x1f0b8adf, PorterDuff.Mode.SRC_ATOP)
                v.invalidate()
            }
            MotionEvent.ACTION_UP -> {
                v.background.clearColorFilter()
                v.invalidate()
            }
        }
        false
    }
}

Version Java:

public static void buttonEffect(View button){
    button.setOnTouchListener(new OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
                    v.invalidate();
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    v.getBackground().clearColorFilter();
                    v.invalidate();
                    break;
                }
            }
            return false;
        }
    });
}
András
la source
2
J'utilise ceci dans mon code et le seul problème que j'ai remarqué jusqu'à présent est que le bouton se comporte bizarrement lorsqu'il est placé dans un ScrollView.
Finnboy11
C'est une solution vraiment superbe et cela devrait être la bonne réponse
Biraj Zalavadia
Comment est-ce mieux? La conception doit être conservée en dehors du code, n'est-ce pas?
Bugs Happen
C'est juste une solution simple à ce problème. Lorsque vous avez beaucoup de boutons et que vous ne voulez pas créer de fichiers XML pour chacun d'entre eux, cela peut être utile.
András
OMG! Imaginez avoir 5 boutons dans un fragment ... Vous aurez tout un tas de ce code passe-partout ... Comment le refactoriser alors? Changer le filtre de couleur pour tous les boutons de toutes les activités? Imho c'est votre prochain développeur ne sera pas si heureux ..
Leo Droidcoder
84

Créez votre AlphaAnimationobjet qui décide de l'ampleur de l'effet de fondu du bouton, puis laissez-le démarrer dans le onClickListenerde vos boutons

Par exemple :

private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.8F);

// some code

public void onClick(View v) {
    v.startAnimation(buttonClick);
}

bien sûr, c'est juste un moyen, pas le plus préféré, c'est juste plus facile

Ahmed Adel Ismail
la source
5
Ce que j'aime dans cette solution, c'est qu'elle ne nécessite pas la création de nombreux sélecteurs, lorsque vous avez de nombreux boutons chacun avec leurs propres images personnalisées.
Pete
2
Cela ne fait pas fondre le bouton lors d'un toucher vers le bas, il ne le fait que pendant une fraction de seconde après que le clic est détecté et que le doigt de l'utilisateur a déjà été levé.
Doug Voss
1
Nice and simple
@Doug Voss, vous pouvez définir la durée de l'animation pour l'allonger
Ahmed Adel Ismail
qu'en est-il de onLongClick et de 'circularReveal'?
Acauã Pitta
45

Vous pouvez simplement utiliser le premier plan pour Viewobtenir un effet cliquable:

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


Pour une utilisation avec un thème sombre, ajoutez également un thème à votre layout(pour que l'effet cliquable soit clair):

android:theme="@android:style/ThemeOverlay.Material.Dark"
Francis
la source
5
La manière la plus simple de mettre en œuvre. Pour info, attribut android: le premier plan n'a aucun effet sur les niveaux d'API inférieurs à 23.
dolgom
1
La solution la plus simple.
Jerry Chong
2
Cela devrait être la réponse acceptée, beaucoup plus simple et cela ajoute le bel effet d'animation d'ondulation.
Tyler
1
@dolgom Pour le niveau d'API <23, utilisez-le sur l'attribut "background". Ainsi: android: background = "? android: attr /
selectableItemBackground
24

Pour rendre votre élément cohérent avec l'apparence du système, essayez de référencer l'attribut système android:attr/selectableItemBackgrounddans la balise d'arrière-plan ou de premier plan de la vue souhaitée:

<ImageView
    ...
    android:background="?android:attr/selectableItemBackground"      
    android:foreground="?android:attr/selectableItemBackground"
    ...
/>

Utilisez les deux attributs pour obtenir l'effet souhaité avant / après le niveau d'API 23 respectivement.

https://stackoverflow.com/a/11513474/4683601

Ely Dantas
la source
2
De loin la solution la plus simple. Merci!
tykom
9

Ou en utilisant une seule image d'arrière-plan, vous pouvez obtenir l'effet de clic en utilisant setOnTouchListener

Deux manières

((Button)findViewById(R.id.testBth)).setOnTouchListener(new OnTouchListener() {

      @Override
        public boolean onTouch(View v, MotionEvent event) {
          switch (event.getAction()) {
              case MotionEvent.ACTION_DOWN: {
                  Button view = (Button) v;
                  view.getBackground().setColorFilter(0x77000000, PorterDuff.Mode.SRC_ATOP);
                  v.invalidate();
                  break;
              }
              case MotionEvent.ACTION_UP:
                  // Your action here on button click
              case MotionEvent.ACTION_CANCEL: {
                  Button view = (Button) v;
                  view.getBackground().clearColorFilter();
                  view.invalidate();
                  break;
              }
          }
          return true;
        }
});

entrez la description de l'image ici

Et si vous ne voulez pas utiliser setOnTouchLister, une autre façon d'y parvenir est

    myButton.getBackground().setColorFilter(.setColorFilter(0xF00, Mode.MULTIPLY);

    StateListDrawable listDrawable = new StateListDrawable();
    listDrawable.addState(new int[] {android.R.attr.state_pressed}, drawablePressed);
    listDrawable.addState(new int[] {android.R.attr.defaultValue}, myButton);

    myButton.setBackgroundDrawable(listDrawable);
Vinayak Bevinakatti
la source
il y a des erreurs de code de la 2ème manière. Qu'est-ce que la fonction getCurrent ()? De plus, myButton n'est pas un Drawable donc il ne peut pas être ajouté en tant qu'état.
Ehtesham Hasan
Merci d'avoir signalé l'erreur. Je l'ai corrigé, et myButton est une instance de la classe Button qui fournit la méthode setBackgroundDrawable et prend les instances Drawable, donc cela fonctionnera.
Vinayak Bevinakatti
Découvrez ma réponse basée sur votre 2ème approche. stackoverflow.com/a/39430738/5229515
Ehtesham Hasan
Cela devrait probablement avoir "return false" à la fin afin qu'il ne consomme pas l'événement et tout onClickListeners supplémentaire peut être appelé.
Doug Voss
3

je veux juste ajouter un autre moyen simple de le faire: si votre ImageButton reste son arrière-plan et que vous ne le définissez pas sur null, il fonctionnera comme un bouton normal et affichera l'animation de clic tout en cliquant exactement comme les autres boutons. l'arrière-plan tant qu'il est toujours là:

<ImageButton
    android:id="@+id/imageButton2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingBottom="1dp"
    android:paddingLeft="1dp"
    android:paddingRight="1dp"
    android:paddingTop="1dp"
    android:src="@drawable/squareicon" />

Les rembourrages ne laisseront pas l'arrière-plan être visible et feront agir le bouton comme les autres boutons.

arianoo
la source
1
cela gardera la bordure du bouton carré autour de l'image si elle est circulaire
MSaudi
3

C'est la meilleure solution que j'ai trouvée en tenant compte de la réponse de @ Vinayak. Toutes les autres solutions présentent des inconvénients différents.

Tout d'abord, créez une fonction comme celle-ci.

void addClickEffect(View view)
{
    Drawable drawableNormal = view.getBackground();

    Drawable drawablePressed = view.getBackground().getConstantState().newDrawable();
    drawablePressed.mutate();
    drawablePressed.setColorFilter(Color.argb(50, 0, 0, 0), PorterDuff.Mode.SRC_ATOP);

    StateListDrawable listDrawable = new StateListDrawable();
    listDrawable.addState(new int[] {android.R.attr.state_pressed}, drawablePressed);
    listDrawable.addState(new int[] {}, drawableNormal);
    view.setBackground(listDrawable);
}

Explication:

getConstantState (). newDrawable () est utilisé pour cloner le Drawable existant sinon le même drawable sera utilisé. En savoir plus ici: Android: Cloner un dessinable afin de créer un StateListDrawable avec des filtres

mutate () est utilisé pour empêcher le clone de Drawable de partager son état avec d'autres instances de Drawable. En savoir plus à ce sujet ici: https://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate ()

Usage:

Vous pouvez passer n'importe quel type de vue (Button, ImageButton, View, etc.) comme paramètre à la fonction et ils obtiendront l'effet de clic qui leur sera appliqué.

addClickEffect(myButton);
addClickEffect(myImageButton);
Ehtesham Hasan
la source
2
Step: set a button in XML with onClick Action:

 <Button
android:id="@+id/btnEditUserInfo"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/txt_height"
android:layout_gravity="center"
android:background="@drawable/round_btn"
android:contentDescription="@string/image_view"
android:onClick="edit_user_info"
android:text="Edit"
android:textColor="#000"
android:textSize="@dimen/login_textSize" />

Step: on button clicked show animation point
//pgrm mark ---- ---- ----- ---- ---- ----- ---- ---- -----  ---- ---- -----

    public void edit_user_info(View view) {

        // show click effect on button pressed
        final AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.8F);
        view.startAnimation(buttonClick);

        Intent intent = new Intent(getApplicationContext(),  EditUserInfo.class);
        startActivity(intent);

    }// end edit_user_info
Vinod Joshi
la source
2

Utilisez RippleDrawable pour un effet de pression / clic sur l'état Material Design.

Pour ce faire, créez un élément ripple en tant que dossier .xml sous / drawable et utilisez-le dans android: background pour toutes les vues.

  • Effet pour l'icône enfoncée / cliquée, utilisez l'effet d'entraînement circulaire, par exemple:

    <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@android:color/darker_gray" />

  • Effet pour la vue cliquée avec la limite du rectangle, nous pouvons ajouter une ondulation sur le dessinable existant comme ci-dessous:

    <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="#000000"> <item android:drawable="@drawable/your_background_drawable"/> </ripple>

giang nguyen
la source
2

Pour toutes les vues

android:background="?android:attr/selectableItemBackground"

Mais pour cardview qui a une utilisation d'élévation

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

Pour l'effet de clic circulaire comme dans la barre d'outils

android:background="?android:attr/actionBarItemBackground"

Vous devez également définir

 android:clickable="true"
 android:focusable="true"
Faizan Khan
la source
0

Faire un ajout mineur à la réponse d'Andràs:

Vous pouvez utiliser postDelayedpour faire durer le filtre de couleur pendant une petite période de temps pour le rendre plus visible:

        @Override
        public boolean onTouch(final View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    v.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
                    v.invalidate();
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    v.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            v.getBackground().clearColorFilter();
                            v.invalidate();
                        }
                    }, 100L);
                    break;
                }
            }
            return false;
        }

Vous pouvez modifier la valeur du délai 100L en fonction de vos besoins.

hiddeneyes02
la source
0

Si vous utilisez un arrière-plan xml au lieu d'IMG, supprimez simplement ceci:

<item>
    <bitmap android:src="@drawable/YOURIMAGE"/>
</item>

de la 1ère réponse que @Ljdawson nous a donnée.

RastaPopuloS
la source