Android OnClickListener: identifica un botón

134

Tengo la actividad:

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

¿Cómo verifico en qué botón se ha hecho clic?

xpepermint
fuente
1
Comparación de cinco formas diferentes de agregar OnClickListeners para varios botones
Suragch,

Respuestas:

199

Aprenderá la forma de hacerlo, de una manera fácil, es:

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

O, si está trabajando con un solo clicklistener, puede hacer:

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

Sin embargo, no recomiendo hacerlo de esa manera, ya que tendrá que agregar uno ifpara cada botón que use. Eso es difícil de mantener.

Cristian
fuente
1
Bueno, en realidad eso no es correcto. Viewno es un Button, pero Buttones un View. Sin embargo, puedes lanzar un Viewa a Button. Tenga en cuenta que la segunda forma de hacerlo no es recomendable ... tal vez que v no sea un Botón, lo que generará una excepción de lanzamiento.
Cristian
2
En realidad, no se recomiendan ambas formas, vea mi respuesta
ognian
En realidad, es bastante simple reemplazar los if, elses con una sola declaración de caso de cambio que activa el id de la vista y los casos son id de R.java
slayton
Me pregunto por qué lanzas v a un botón de todos modos. getId () también se define para Vistas. Por lo tanto, realmente no recomendaría el segundo método, ¡pero prefiero la solución de Christian!
nuala
77

O puede intentar lo mismo pero sin oyentes. En la definición XML de su botón:

android:onClick="ButtonOnClick"

Y en su código defina el método ButtonOnClick:

public void ButtonOnClick(View v) {
    switch (v.getId()) {
      case R.id.button1:
        doSomething1();
        break;
      case R.id.button2:
        doSomething2();
        break;
      }
}
Chronos
fuente
3
Mucho más limpio que las otras respuestas que usan un montón de controladores de eventos, ifdeclaraciones y oyentes. Los oyentes son excelentes si los botones se crean en tiempo de ejecución, pero a menudo ese no es el caso.
Dennis
66
Si bien es un enfoque diferente interesante, los enlaces XML para los oyentes son difíciles en las esquinas con Fragments, ya que la devolución de llamada debe residir en la actividad (no en el fragmento).
donfede
Mi problema es doSomething2 () no se puede alcanzar sin lanzar una InvocationTargetException o una NullPointerException (o ambas).
Quasaur
1
Solo una nota al margen: la afirmación "sin oyentes" aquí está equivocada. Solo está declarando el oyente en XML, eso es todo.
Hubert Grzeskowiak
42

Yo prefiero:

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

Y entonces:

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

Switch- casees más fácil de mantener que if- else, y esta implementación no requiere hacer muchas variables de clase.

Saad Farooq
fuente
Esto funcionó perfectamente. Debe implementar OnClickListener-android.view.View y no OnClickListener-android.content.DialogInterface
gkiko
16

Cinco formas de conectar un oyente de eventos es un excelente artículo que describe las diversas formas de configurar un solo oyente de eventos. Permítanme expandir eso aquí para múltiples oyentes.

1. Clase de miembro

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 interfaz

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. Clase 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. Implementación en actividad

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 en Ver diseño 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;
        }
    }
}

Y 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" />
Suragch
fuente
12

Si no desea guardar instancias del botón 2 en el código de clase, siga esta MEJOR manera (¡esto es más claro y 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
fuente
12

Otra forma de hacerlo es un solo oyente de la actividad, como este:

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

Me gusta hacerlo con un solo IF en lugar de cambiar, pero si lo prefieres, entonces debes hacer:

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

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

La mejor manera es mediante switch-ing entre v.getId (). Tener un OnClickListener anónimo separado para cada botón está ocupando más memoria. Transmitir vista al botón es innecesario. Usar if-else cuando el cambio es posible es más lento y más difícil de leer. En la fuente de Android, a menudo puede notar la comparación de las referencias de if-else:

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

No sé exactamente por qué eligieron de esta manera, pero también funciona.

ognian
fuente
porque ya no es posible desde v14 donde los identificadores no se tratan no es constante
user1324936
@ognian Seguí hasta aquí porque dijiste que la respuesta principal usa enfoques obsoletos. Hoy en día con Android 5.0 Lollipop lanzado, ¿su respuesta sigue siendo cierta o el tiempo la convirtió en una falacia, como sugiere el comentario anterior? Realmente no sé qué pensar o qué dirección tomar desde aquí.
SebasSBM
7

use setTag ();

Me gusta esto:

@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;   
    }     
}     
usuario2644305
fuente
Vine aquí buscando un método para pasar parámetros adicionales a un controlador, esto es exactamente lo que quería. La etiqueta se puede declarar en Marcado.
tasador el
4

Además de la respuesta de Cristian C (lo siento, no tengo la capacidad de hacer comentarios), si crea un controlador para ambos botones, puede comparar directamente v con b1 y b2, o si desea comparar por ID, no es necesario convertir v en Button (View también tiene el método getId ()), y de esa manera no hay que preocuparse por la excepción de conversión.

DonSteep
fuente
Otra opción sería hacer un "if (v instanceof Button) {// Cast to Button y hacer cosas aquí}"
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
fuente
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();
    }
}

Mira este artículo para más detalles

usuario7925882
fuente
Esto es más o menos solo una repetición de algunas de las respuestas existentes.
Pang