安卓 OnClickListener - 如何识别一个按钮

134

我有一个活动:

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

我如何检查哪个按钮被点击了?


1
比较五种不同的方式,为多个按钮添加OnClickListeners - Suragch
11个回答

198

你将学习如何以简单的方式完成它:

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

如果你只使用一个click listener,你可以这样做:

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

虽然这样做不是我推荐的方法,因为每次你使用一个按钮都需要添加一个if语句,这很难维护。


1
其实那并不正确。View不是Button,但是ButtonView。尽管如此,你可以将View强制转换为Button。请记住第二种方法并不推荐使用... 可能那个v并不是一个Button,这会引发转换异常。 - Cristian
2
实际上,这两种方法都不被推荐,可以看看我的回答。 - ognian
实际上,用一个 switch case 语句替换 if 和 else 是非常简单的,你只需要在视图的 id 上进行切换,而 case 则是来自 R.java 的 id。 - slayton
只是好奇为什么你将v强制转换为Button。getId()也适用于Views。因此,我真的不建议使用第二种方法,而更喜欢Christian的解决方案! - nuala

77

或者您可以尝试相同的方法,但不使用监听器。 在您的按钮XML定义上:

android:onClick="ButtonOnClick"

在您的代码中定义方法ButtonOnClick

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

3
比其他使用了大量事件处理程序、if语句和监听器的答案更为简洁。如果按钮是在运行时创建的,那么监听器很好用,但这通常并不是情况。 - Dennis
6
虽然这是一种有趣的不同方法,但针对Fragment的XML监听器挂钩存在一些问题,因为回调必须驻留在活动中(而不是片段中)。 - donfede
我的问题是doSomething2()方法无法被调用,除非抛出InvocationTargetException或NullPointerException(或两者都有)。 - Quasaur
1
只是一点小注:这里的说法“没有侦听器”是错误的。你只是在 XML 中声明了侦听器而已。 - Hubert Grzeskowiak

42

我更喜欢:

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

然后:

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

Switch-caseif-else更易于维护,而且这种实现不需要创建很多类变量。


这个完美地运行了。你需要实现 OnClickListener-android.view.View 而不是 _OnClickListener-android.content.DialogInterface_。 - gkiko

16

Five Ways to Wire Up an Event Listener是一篇很棒的文章,概述了各种设置单个事件监听器的方式。我在这里将其扩展到多个听众。

1. 成员类

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. 接口类型

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. 匿名内部类

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. 活动中的实现

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. 在视图布局中使用属性绑定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;
        }
    }
}

并在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

另一种方法是在活动中使用单个监听器,代码如下:

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

我喜欢使用单个 IF 语句而不是 switch-else,但如果你更喜欢后者,那么你应该这样做:

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

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

12

如果您不想在类代码中保存2个按钮的实例,请按照这种更好的方式操作(这样更清晰快速!):

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

9
最好的方法是通过在v.getId()之间使用switch。为每个按钮单独创建匿名OnClickListener会占用更多内存。将View强制转换为Button是不必要的。如果可能,使用switch而不是if-else会更慢且难以阅读。在Android的源代码中,您经常会注意到通过if-else比较引用:
if (b1 == v) {
 // ...
} else if (b2 == v) {

我不确定为什么他们选择了这种方式,但它也起作用。


因为自v14版本起,ID不再被视为常量,所以这已经不再可能。 - user1324936
@ognian,我跟到这里,因为你说主要答案使用了过时的方法。现在随着Android 5.0棒棒糖的发布,你的答案还正确吗?或者时间让它变成了谬论,就像上面的评论所暗示的那样?我真的不知道该怎么想,或者从这里采取哪个方向。 - SebasSBM

7

使用setTag()函数;

像这样:

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

我来这里是为了寻找一种将额外参数传递给处理程序的方法,这正是我想要的。该标记可以在标记中声明。 - cessor

4

除了Cristian C的回答(抱歉,我没有评论的能力),如果你为两个按钮创建一个处理程序,你可以直接将v与b1和b2进行比较,或者如果你想按ID进行比较,你不需要将v转换为Button(View也有getId()方法),这样就不用担心强制转换异常。


另一个选项是使用 "if (v instanceof Button) { // 将其转换为 Button 并在此处执行操作 }"。 - Andy Zhang

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接