Android OnClickListener - identifier un bouton


134

J'ai l'activité:

public class Mtest extends Activity {
  Button b1;
  Button b2;
  public void onCreate(Bundle savedInstanceState) {
    ...
    b1 = (Button) findViewById(R.id.b1);
    b2 = (Button) findViewById(R.id.b2);
    b1.setOnClickListener(myhandler);
    b2.setOnClickListener(myhandler);
    ...
  }
  View.OnClickListener myhandler = new View.OnClickListener() {
    public void onClick(View v) {
      // MY QUESTION STARTS HERE!!!
      // IF b1 do this
      // IF b2 do this
      // MY QUESTION ENDS HERE!!!
    }
  }
}

Comment vérifier quel bouton a été cliqué?


1
Comparaison de cinq façons différentes d'ajouter des OnClickListeners pour plusieurs boutons
Suragch

Réponses:


199

Vous apprendrez comment le faire, d'une manière simple, est:

public class Mtest extends Activity {
  Button b1;
  Button b2;
  public void onCreate(Bundle savedInstanceState) {
    ...
    b1 = (Button) findViewById(R.id.b1);
    b2 = (Button) findViewById(R.id.b2);
    b1.setOnClickListener(myhandler1);
    b2.setOnClickListener(myhandler2);
    ...
  }
  View.OnClickListener myhandler1 = new View.OnClickListener() {
    public void onClick(View v) {
      // it was the 1st button
    }
  };
  View.OnClickListener myhandler2 = new View.OnClickListener() {
    public void onClick(View v) {
      // it was the 2nd button
    }
  };
}

Ou, si vous travaillez avec un seul écouteur de clics, vous pouvez faire:

View.OnClickListener myOnlyhandler = new View.OnClickListener() {
  public void onClick(View v) {
      switch(v.getId()) {
        case R.id.b1:
          // it was the first button
          break;
        case R.id.b2:
          // it was the second button
          break;
      }
  }
}

Cependant, je ne recommande pas de le faire de cette façon car vous devrez ajouter un ifpour chaque bouton que vous utilisez. C'est difficile à maintenir.


1
Eh bien, en fait, ce n'est pas correct. Viewn'est pas un Button, mais Buttonest un View. Cependant, vous pouvez lancer un Viewen un Button. Gardez à l'esprit que la deuxième façon de le faire n'est pas recommandée ... peut-être que v peut ne pas être un Button, ce qui générera une exception de cast.
Cristian

2
En fait, les deux méthodes ne sont pas recommandées, voir ma réponse
ognian

C'est en fait assez simple de remplacer le if, elses par une seule instruction switch case que vous allumez l'id de la vue et les cases sont des id de R.java
slayton

Je me demande simplement pourquoi vous lancez v sur un bouton de toute façon. getId () est également défini pour les vues. Par conséquent, je ne recommanderais vraiment pas la 2ème méthode mais je préfère la solution de Christian!
nuala

77

Ou vous pouvez essayer la même chose mais sans auditeurs. Sur la définition XML de votre bouton:

android:onClick="ButtonOnClick"

Et dans votre code définissez la méthode ButtonOnClick:

public void ButtonOnClick(View v) {
    switch (v.getId()) {
      case R.id.button1:
        doSomething1();
        break;
      case R.id.button2:
        doSomething2();
        break;
      }
}

3
Beaucoup plus propre que les autres réponses qui utilisent un tas de gestionnaires d'événements, d' ifinstructions et d'écouteurs. Les écouteurs sont parfaits si les boutons sont créés au moment de l'exécution, mais ce n'est souvent pas le cas.
Dennis

6
Bien qu'une approche différente soit intéressante, les hooks XML pour les écouteurs sont approximatifs avec Fragments, car le rappel doit résider dans l'activité (pas le fragment).
donfede

Mon problème est que doSomething2 () ne peut pas être atteint sans lancer une InvocationTargetException ou une NullPointerException (ou les deux).
Quasaur

1
Juste une remarque: l'affirmation "sans auditeurs" ici est fausse. Vous ne déclarez l'auditeur qu'en XML, c'est tout.
Hubert Grzeskowiak

42

Je préfère:

class MTest extends Activity implements OnClickListener {
    public void onCreate(Bundle savedInstanceState) {
    ...
    Button b1 = (Button) findViewById(R.id.b1);
    Button b2 = (Button) findViewById(R.id.b2);
    b1.setOnClickListener(this);
    b2.setOnClickListener(this);
    ...
}

Puis:

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.b1:
            ....
            break;
        case R.id.b2:
            ....
            break;
    }   
}

Switch- caseest plus facile à maintenir que if- else, et cette implémentation ne nécessite pas la création de nombreuses variables de classe.


Cela a parfaitement fonctionné. Vous devez implémenter OnClickListener-android.view.View et non OnClickListener-android.content.DialogInterface
gkiko

16

Five Ways to Wire Up an Event Listener est un excellent article présentant les différentes façons de configurer un seul écouteur d'événement. Permettez-moi de développer cela ici pour plusieurs auditeurs.

1. Classe de membre

public class main extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //attach an instance of HandleClick to the Button
        HandleClick handleClick = new HandleClick();
        findViewById(R.id.button1).setOnClickListener(handleClick);
        findViewById(R.id.button2).setOnClickListener(handleClick);
    }    
    private class HandleClick implements OnClickListener{
        public void onClick(View view) {
            switch(view.getId()) {
            case R.id.button1:
                // do stuff
                break;
            case R.id.button2:
                // do stuff
                break;
            }
        }
    }
}

2. Type d'interface

public class main extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(handleClick);
        findViewById(R.id.button2).setOnClickListener(handleClick);
    }
    private OnClickListener handleClick = new OnClickListener() {
        public void onClick(View view) {
            switch (view.getId()) {
            case R.id.button1:
                // do stuff
                break;
            case R.id.button2:
                // do stuff
                break;
            }
        }
    };
}

3. Classe intérieure anonyme

public class main extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                // do stuff
            }
        });
        findViewById(R.id.button2).setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                // do stuff
            }
        });
    }
}

4. Mise en œuvre en activité

public class main extends Activity implements OnClickListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
    }
    public void onClick(View view) {
        switch (view.getId()) {
        case R.id.button1:
            // do stuff
            break;
        case R.id.button2:
            // do stuff
            break;
        }
    }
}

5. Attribut dans la disposition de vue pour les événements OnClick

public class main extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    public void HandleClick(View view) {
        switch (view.getId()) {
        case R.id.button1:
            // do stuff
            break;
        case R.id.button2:
            // do stuff
            break;
        }
    }
}

Et en xml:

<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="HandleClick" />
<Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="HandleClick" />

12

Si vous ne souhaitez pas enregistrer les instances du bouton 2 dans le code de la classe, suivez cette meilleure méthode (c'est plus clair et rapide !!):

public void buttonPress(View v) {
  switch (v.getId()) {
    case R.id.button_one:
        // do something
        break;
    case R.id.button_two:
        // do something else
        break;
    case R.id.button_three:
        // i'm lazy, do nothing
        break;
  }
}

12

Une autre façon de le faire est un seul auditeur de l'activité, comme ceci:

public class MyActivity extends Activity implements OnClickListener {
    .......  code

    //my listener
    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.mybutton) { 
            DoSomething();
            return;
        }

        if (v.getId() == R.id.mybutton2) { 
            DoSomething2();
            return;
        }
    }
}

J'aime le faire avec un IF unique au lieu de switch-else, mais si vous préférez cela, vous devriez le faire:

//my listener
@Override
public void onClick(View v) {
    switch(v.getId()) {
        case R.id.mybutton:
        { 
             DoSomething();
             break;
        }

        case R.id.mybutton2:
        {
            DoSomething();
            break;
        }
    }
}

9

Le meilleur moyen est de switchpasser entre v.getId (). Avoir un OnClickListener anonyme séparé pour chaque bouton prend plus de mémoire. Il n'est pas nécessaire de diffuser la vue sur le bouton. L'utilisation de if-else lorsque le commutateur est possible est plus lente et plus difficile à lire. Dans la source d'Android, vous pouvez souvent remarquer la comparaison des références par if-else:

if (b1 == v) {
 // ...
} else if (b2 == v) {

Je ne sais pas exactement pourquoi ils ont choisi cette voie, mais cela fonctionne aussi.


car ce n'est plus possible depuis la v14 où les identifiants ne sont pas traités comme des constantes
user1324936

@ognian J'ai suivi ici parce que vous avez dit que la réponse principale utilise des approches obsolètes. De nos jours, avec la sortie d'Android 5.0 Lollipop, votre réponse est-elle toujours vraie, ou le temps l'a fait devenir une faille, comme le suggère le commentaire ci-dessus? Je ne sais vraiment pas quoi penser, ni quelle direction prendre à partir d'ici.
SebasSBM

7

utilisez setTag ();

comme ça:

@Override    
public void onClick(View v) {     
    int tag = (Integer) v.getTag();     
    switch (tag) {     
    case 1:     
        System.out.println("button1 click");     
        break;     
    case 2:     
        System.out.println("button2 click");     
       break;   
    }     
}     

Je suis venu ici à la recherche d'une méthode pour passer des paramètres supplémentaires à un gestionnaire, c'est exactement ce que je voulais. La balise peut être déclarée dans Markup.
cessor

4

En plus de la réponse de Cristian C (désolé, je n'ai pas la possibilité de faire des commentaires), si vous créez un gestionnaire pour les deux boutons, vous pouvez directement comparer v à b1 et b2, ou si vous souhaitez comparer par l'ID, vous n'ont pas besoin de convertir v en Button (View a également la méthode getId ()), et de cette façon, il n'y a pas de souci d'exception de conversion.


Une autre option serait de faire un "if (v instanceof Button) {// Cast to Button and do stuff here}"
Andy Zhang

4
Button mybutton = new Button(ViewPagerSample.this);
mybutton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
            // TODO Auto-generated method stub
    }
});

1
Button button1 = (Button)findViewById(R.id.button1);
button1.setOnClickListener(this);

@Override
public void onClick(View v) {
    // TODO Auto-generated method stub
    if(v.getId() == R.id.button1){
        Toast.makeText(context, "Button 1 Click", Toast.LENGTH_LONG).show();
    }
}

Consultez cet article pour plus de détails


Ceci est plus ou moins juste une répétition de certaines des réponses existantes.
Pang
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.