Android OnClickListener - zidentyfikuj przycisk

134

Mam aktywność:

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

Jak sprawdzić, który przycisk został kliknięty?

xpepermint
źródło
1
Porównanie pięciu różnych sposobów dodawania OnClickListeners dla wielu przycisków
Suragch

Odpowiedzi:

199

Dowiesz się, jak to zrobić, w prosty sposób:

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

Jeśli pracujesz tylko z jednym nasłuchiwaniem kliknięć, możesz:

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

Chociaż nie polecam tego w ten sposób, ponieważ będziesz musiał dodać znak ifdla każdego używanego przycisku. Trudno to utrzymać.

Cristian
źródło
1
Właściwie to nie jest poprawne. Viewnie jest Button, ale Buttonjest View. Chociaż możesz rzucić a Viewdo Button. Pamiętaj, że drugi sposób zrobienia tego nie jest zalecany ... może to v może nie być Button, który wygeneruje wyjątek rzutowania.
Cristian
2
Właściwie oba sposoby nie są zalecane, zobacz moją odpowiedź
ognian
Właściwie całkiem łatwo jest zamienić if, elses na pojedynczy przełącznik przypadku oświadczenia, że ​​włączasz identyfikator widoku, a skrzynki są identyfikatory z R.java
slayton.
Zastanawiam się tylko, dlaczego i tak rzuciłeś v na Button. getId () jest również zdefiniowane dla widoków. Dlatego naprawdę nie polecałbym drugiej metody, ale wolałbym rozwiązanie Christiana!
nuala
77

Możesz też spróbować tego samego, ale bez słuchaczy. W definicji XML przycisku:

android:onClick="ButtonOnClick"

A w swoim kodzie zdefiniuj metodę ButtonOnClick:

public void ButtonOnClick(View v) {
    switch (v.getId()) {
      case R.id.button1:
        doSomething1();
        break;
      case R.id.button2:
        doSomething2();
        break;
      }
}
Chronos
źródło
3
Znacznie czystsze niż inne odpowiedzi, które używają wielu programów obsługi zdarzeń, ifinstrukcji i słuchaczy. Słuchacze są świetne, jeśli przyciski są tworzone w czasie wykonywania, ale często tak nie jest.
Dennis
6
Chociaż jest to interesujące inne podejście, zaczepy XML dla słuchaczy są szorstkie za rogami z Fragments, ponieważ wywołanie zwrotne musi znajdować się w działaniu (nie we fragmencie).
donfede
Prawdopodobnie nie można osiągnąć metody doSomething2 () bez zgłaszania wyjątku InvocationTargetException lub NullPointerException (lub obu).
Quasaur,
1
Na marginesie: stwierdzenie „bez słuchaczy” jest błędne. Deklarujesz tylko odbiornik w XML, to wszystko.
Hubert Grzeskowiak
42

Wolę:

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

I wtedy:

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

Switch- casejest łatwiejszy w utrzymaniu niż if- else, a ta implementacja nie wymaga tworzenia wielu zmiennych klasowych.

Saad Farooq
źródło
To działało doskonale. Musisz zaimplementować OnClickListener-android.view.View, a nie OnClickListener-android.content.DialogInterface
gkiko
16

Five Ways to Wire Up an Event Listener to świetny artykuł omawiający różne sposoby konfigurowania pojedynczego nasłuchiwania zdarzeń. Pozwólcie, że rozwinę to tutaj dla wielu słuchaczy.

1. Klasa członkowska

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. Typ interfejsu

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. Anonimowa klasa wewnętrzna

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. Wdrożenie w działaniu

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. Atrybut w układzie widoku dla zdarzeń 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;
        }
    }
}

A w 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" />
Suragch
źródło
12

Jeśli nie chcesz zapisywać instancji przycisku 2 w kodzie klasy, postępuj w ten LEPSZY sposób (jest to bardziej przejrzyste i szybkie !!):

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;
  }
}
lory105
źródło
12

Innym sposobem na zrobienie tego jest pojedynczy słuchacz z działania, na przykład:

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

Lubię to robić z pojedynczym IF zamiast przełącznikiem-else, ale jeśli wolisz, powinieneś zrobić:

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

        case R.id.mybutton2:
        {
            DoSomething();
            break;
        }
    }
}
ruhalde
źródło
9

Najlepszym sposobem jest switchominięcie między v.getId (). Posiadanie oddzielnego anonimowego OnClickListener dla każdego przycisku zajmuje więcej pamięci. Przesyłanie widoku do przycisku jest niepotrzebne. Używanie if-else, gdy przełącznik jest możliwy, jest wolniejsze i trudniejsze do odczytania. W źródle Androida często można zauważyć porównanie odniesień według warunku if-else:

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

Nie wiem dokładnie, dlaczego wybrali ten sposób, ale to też działa.

ognian
źródło
ponieważ nie jest to już możliwe od wersji 14, w której identyfikatory nie są traktowane, nie są stałe
user1324936
@ognian Sprawdziłem tutaj, ponieważ powiedziałeś, że główna odpowiedź wykorzystuje przestarzałe podejście. W dzisiejszych czasach, gdy wydano Androida 5.0 Lollipop, czy Twoja odpowiedź jest nadal prawdziwa, czy też czas sprawił, że stała się fałszywa, jak sugeruje powyższy komentarz? Naprawdę nie wiem, co o tym myśleć, ani w jakim kierunku iść stąd.
SebasSBM
7

użyj setTag ();

lubię to:

@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;   
    }     
}     
user2644305
źródło
Przyszedłem tutaj, szukając metody przekazania dodatkowych parametrów do programu obsługi, dokładnie tego chciałem. Tag można zadeklarować w Markup.
cesor
4

Oprócz odpowiedzi Cristiana C (przepraszam, nie mam możliwości komentowania), jeśli utworzysz jedną obsługę dla obu przycisków, możesz bezpośrednio porównać v do b1 i b2, lub jeśli chcesz porównać według identyfikatora, nie trzeba rzutować v na Button (View ma również metodę getId ()), dzięki czemu nie ma obaw o wyjątek rzutowania.

DonSteep
źródło
Inną opcją byłoby wykonanie „if (v instanceof Button) {// Cast to Button i rób rzeczy tutaj}”
Andy Zhang,
4
Button mybutton = new Button(ViewPagerSample.this);
mybutton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
            // TODO Auto-generated method stub
    }
});
Tai Nguyen
źródło
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();
    }
}

Więcej informacji znajdziesz w tym artykule

user7925882
źródło
To mniej więcej powtórzenie niektórych istniejących odpowiedzi.
Pang