Android OnClickListener - identifique um botão

134

Eu tenho a atividade:

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

Como verifico qual botão foi clicado?

xpepermint
fonte
1
Comparação de cinco maneiras diferentes para adicionar OnClickListeners para vários botões
Suragch

Respostas:

199

Você aprenderá a maneira de fazê-lo, de uma maneira fácil, é:

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, se você estiver trabalhando com apenas um listener de cliques, poderá:

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

No entanto, eu não recomendo fazê-lo dessa maneira, pois você precisará adicionar um ifpara cada botão que usar. Isso é difícil de manter.

Cristian
fonte
1
Bem, na verdade isso não está correto. Viewnão é um Button, mas Buttoné um View. No entanto, você pode converter um Viewpara um Button. Lembre-se de que a segunda maneira de fazer isso não é recomendada ... talvez o v não seja um botão, o que gerará uma exceção de conversão.
Cristian
2
Na verdade, os dois lados não são recomendados, veja a minha resposta
Ognian
Sua realmente muito simples para substituir o caso, elses com uma única instrução caso interruptor que liga o ID da vista e os casos são ID de partir R.java
slayton
Apenas querendo saber por que você lança v para um botão de qualquer maneira. getId () também está definido para Views. Portanto, eu realmente não recomendaria o segundo método, mas prefiro a solução de Christian!
Nuala 03/04
77

Ou você pode tentar o mesmo, mas sem ouvintes. Na sua definição XML de botão:

android:onClick="ButtonOnClick"

E no seu código, defina o método ButtonOnClick:

public void ButtonOnClick(View v) {
    switch (v.getId()) {
      case R.id.button1:
        doSomething1();
        break;
      case R.id.button2:
        doSomething2();
        break;
      }
}
Chronos
fonte
3
Muito mais limpo do que as outras respostas que usam vários manipuladores de eventos, ifdeclarações e ouvintes. Os ouvintes são ótimos se os botões são criados em tempo de execução, mas esse geralmente não é o caso.
Dennis
6
Embora seja uma abordagem diferente e interessante, os ganchos XML para ouvintes são irregulares com Fragments, pois o retorno de chamada deve residir na atividade (não no fragmento).
donfede
Meu problema é que doSomething2 () não pode ser alcançado sem gerar InvocationTargetException ou NullPointerException (ou ambos).
Quasaur
1
Apenas uma nota de rodapé: a afirmação "sem ouvintes" aqui está errada. Você está apenas declarando o ouvinte em XML, só isso.
Hubert Grzeskowiak
42

Eu prefiro:

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 depois:

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

Switch- caseé mais fácil de manter do que if- else, e essa implementação não requer muitas variáveis ​​de classe.

Saad Farooq
fonte
Isso funcionou perfeitamente. Você precisa implementar OnClickListener-android.view.View e não OnClickListener-android.content.DialogInterface
gkiko
16

Cinco maneiras de conectar um ouvinte de evento é um ótimo artigo que mostra as várias maneiras de configurar um único ouvinte de evento. Deixe-me expandir isso aqui para vários ouvintes.

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 de 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 interna anônima

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. Implementação na atividade

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. Atributo no layout da vista para eventos 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 em 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
fonte
12

Se você não deseja salvar instâncias do botão 2 no código da classe, siga esta MELHOR maneira (isso é mais claro e rápido !!):

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
fonte
12

Outra maneira de fazer isso é um único ouvinte da atividade, assim:

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

Eu gosto de fazê-lo com IF único em vez de alternar com outra opção, mas se você preferir, deve fazer:

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

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

A melhor maneira é switchalternar entre v.getId (). Ter OnClickListener anônimo separado para cada botão está ocupando mais memória. A transmissão de exibição para o botão é desnecessária. Usar if-else quando a opção é possível é mais lento e difícil de ler. Na fonte do Android, você pode observar a comparação das referências por if-else:

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

Não sei exatamente por que eles escolheram esse caminho, mas também funciona.

ognian
fonte
porque não é mais possível desde a v14 em que os IDs não são tratados como constantes
#
@ognian Eu segui até aqui porque você disse que a resposta principal usa abordagens obsoletas. Atualmente, com o Android 5.0 Lollipop lançado, sua resposta ainda é verdadeira ou o tempo tornou-o uma falácia, como sugere o comentário acima? Realmente não sei o que pensar, ou qual direção seguir daqui.
SebasSBM
7

use setTag ();

como isso:

@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
fonte
Eu vim aqui procurando um método para passar parâmetros adicionais para um manipulador, é exatamente isso que eu queria. A tag pode ser declarada na marcação.
cessora
4

Além da resposta de Cristian C (desculpe, eu não tenho a capacidade de fazer comentários), se você criar um manipulador para os dois botões, poderá comparar diretamente v com b1 e b2 ou se quiser comparar com o ID, não precisa converter v para Button (a View também possui o método getId ()) e, dessa forma, não há preocupação com a exceção de conversão.

DonSteep
fonte
Outra opção seria fazer um "if (v instanceof Button) {// Transmitir para o Button e fazer as coisas aqui}"
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
fonte
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();
    }
}

Confira este artigo para mais detalhes

user7925882
fonte
Isso é mais ou menos apenas uma repetição de algumas das respostas existentes.
Pang