Android OnClickListener: identifica un pulsante


134

Ho l'attività:

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

Come posso verificare quale pulsante è stato cliccato?


1
Confronto tra cinque diversi modi per aggiungere OnClickListeners per più pulsanti
Suragch

Risposte:


199

Imparerai come farlo, in modo semplice, è:

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

Oppure, se lavori con un solo listener di clic, puoi fare:

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

Tuttavia, non ti consiglio di farlo in questo modo poiché dovrai aggiungere un ifper ogni pulsante che usi. È difficile da mantenere.


1
Bene, in realtà non è corretto. Viewnon è un Button, ma Buttonè un View. Tuttavia, puoi lanciare Viewa a Button. Tieni presente che il secondo modo per farlo non è raccomandato ... forse v potrebbe non essere un pulsante, che genererà un'eccezione di trasmissione.
Cristian,

2
In realtà entrambi i modi non sono raccomandati, vedi la mia risposta
ognian

In realtà è abbastanza semplice sostituire if, elses con una singola istruzione case switch che attiva l'id della vista e i casi sono id di R.java
slayton

Mi chiedo solo perché hai lanciato v su un pulsante comunque. getId () è definito anche per Views. Quindi non consiglierei davvero il secondo metodo, ma preferisco la soluzione di Christian!
nuala,

77

Oppure puoi provare lo stesso ma senza ascoltatori. Sul tuo pulsante Definizione XML:

android:onClick="ButtonOnClick"

E nel tuo codice definisci il metodo ButtonOnClick:

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

3
Molto più pulito delle altre risposte che usano un sacco di gestori di eventi, ifdichiarazioni e ascoltatori. Gli ascoltatori sono fantastici se i pulsanti vengono creati in fase di esecuzione, ma spesso non è così.
Dennis,

6
Mentre un approccio diverso e interessante, gli hook XML per i listener sono approssimativi con Fragments, poiché il callback deve risiedere nell'attività (non nel frammento).
donfede,

Il mio problema è che doSomething2 () non può essere raggiunto senza lanciare InvocationTargetException o NullPointerException (o entrambi).
Quasaur,

1
Solo un sidenote: l'affermazione "senza ascoltatori" qui è sbagliata. Stai solo dichiarando l'ascoltatore in XML, tutto qui.
Hubert Grzeskowiak,

42

Preferisco:

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

E poi:

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

Switch- caseè più facile da mantenere di if- elsee questa implementazione non richiede la creazione di molte variabili di classe.


Questo ha funzionato perfettamente. Devi implementare OnClickListener-android.view.View e non OnClickListener-android.content.DialogInterface
gkiko

16

Cinque modi per collegare un ascoltatore di eventi è un ottimo articolo che riassume i vari modi per impostare un singolo listener di eventi. Vorrei espanderlo qui per più ascoltatori.

1. Classe membro

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. Tipo di interfaccia

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

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. Implementazione in Attività

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. Attributo in Visualizza layout per eventi 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;
        }
    }
}

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

Se non vuoi salvare le istanze del pulsante 2 nel codice della classe, segui questo MEGLIO modo (questo è più chiaro e veloce !!):

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

Un altro modo di farlo è un singolo ascoltatore per attività, in questo modo:

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

Mi piace farlo con IF singolo invece di switch-else, ma se lo preferisci, allora dovresti fare:

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

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

9

Il modo migliore è switch-ing tra v.getId (). Avere OnClickListener anonimo separato per ciascun pulsante sta occupando più memoria. Casting View to Button non è necessario. L'uso di if-else quando è possibile il passaggio è più lento e più difficile da leggere. Nella fonte di Android puoi spesso notare il confronto dei riferimenti con if-else:

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

Non so esattamente perché abbiano scelto in questo modo, ma funziona anche.


perché non è più possibile dal v14 in cui gli id ​​non sono trattati non costanti
user1324936

@ognian Ho seguito fino a qui perché hai detto che la risposta principale utilizza approcci deprecati. Al giorno d'oggi con Android 5.0 Lollipop rilasciato, la tua risposta è ancora vera o il tempo è diventato falso, come suggerisce il commento sopra? Non so davvero cosa pensare o quale direzione prendere da qui.
SebasSBM,

7

usa setTag ();

come questo:

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

Sono venuto qui alla ricerca di un metodo per passare parametri aggiuntivi a un gestore, questo è esattamente quello che volevo. Il tag può essere dichiarato in Markup.
cessatore

4

Oltre alla risposta di Cristian C (mi dispiace, non ho la possibilità di commentare), se crei un gestore per entrambi i pulsanti, puoi confrontare direttamente v con b1 e b2 o se vuoi confrontare con l'ID, tu non è necessario eseguire il cast di v su Button (View ha anche il metodo getId ()), e in questo modo non si deve preoccupare dell'eccezione di cast.


Un'altra opzione sarebbe quella di fare un "if (v instanceof Button) {// Cast to Button e fare cose qui}"
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();
    }
}

Controlla questo articolo per maggiori dettagli


Questo è più o meno solo una ripetizione di alcune delle risposte esistenti.
Pang
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.