安卓 - 两个 onClick 监听器和一个按钮

5
我是一位能够翻译文本的助手。
我有一个自定义的TextView,它是可点击的。为了根据点击更改其外观,它定义了自己的onClick处理程序。然而,如果我在活动中定义第二个onClick处理程序以基于按钮执行某些操作,则只会调用其中一个onClick函数。 onClick是一个void函数-是否有任何方法可以说我没有处理这个点击,请将其传递给其他onClick处理程序?
为了更清晰,以下是代码:
在扩展TextView的MyCheckButton内部,我有:
    setOnClickListener( mClickListener );

    private OnClickListener mClickListener = new OnClickListener() {
        public void onClick(View v) {
            toggle();
        }
    };

然而,当我将MyCheckButton包含在我的Activity中时,当它被点击时我需要执行一些操作,因此我会给它附加另一个OnClickListener:

MyCheckButton button= (MyCheckButtonButton) findViewById(R.id.cb);
button.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {
        // do something in the app
    }

});

通过两次调用 setOnClickListener 方法,似乎我正在替换原始监听器,因此不会调用更改外观的 toggle() 方法。如果该按钮已经使用 onClick 处理程序更改其外观,则当单击该按钮时,我应该如何在我的活动中执行某些操作?我以为我会简单地看到两个 OnClickListeners 都被调用。

是的,我认为你说得对,你还可以尝试在xml文件中加入“onClick”属性,看看在设置了“onClickListener”后是否仍会调用你的方法。 - Nathan Schwermann
我猜这不是一个事件冒泡的问题,我的问题是你不能给同一个视图添加两个OnClickListeners吗???在其他地方这是标准做法,所以我很困惑。 - user317033
如果我使用xml onClick,setOnClickListener会覆盖它。 - user317033
8个回答

7

如果您需要多个侦听器,则我会这样做,注册一个知道其他侦听器的侦听器。第一个(实际注册的)将需要根据事件的条件知道何时委派给其他侦听器。实际上,没有必要有两个 OnClickListener 类。第二个类可以实现您想要的任何接口。此外,没有必要为您所需的创建特殊接口。

public class MyClickListener implements OnClickListener{
  private SomeCustomClass mSecondListener = new SomeCustomClass();
  public void onClick(View v){
    if (needToForward){
      mSecondListener.handleClick(v);
    }else{
      //handle the click
    }
  }
}

然后,在您的活动代码中,您将这样做。
MyClickListener lstn = new MyClickListener();
mCheckBox.setOnClickListener(lstn);

你觉得这个方法行不行?

或者,如果你愿意的话,第二个类也可以实现OnClickListener接口。

另外,如果你需要真正的冒泡效果,你可以定义自己的接口,支持将多个点击监听器添加到一个实现了OnClickListener接口的中间类中。从那里,在那个类的onClick()方法中,你会遍历已注册的监听器并调用适当的方法。


我会看一下,我对Java还很新,所以这对我来说不是显而易见的。最后一个选项可能有用,以防这种情况经常发生。我还考虑使用应用程序对象来注册侦听器。 - user317033
这里的第一个建议可能是最干净、最简单的解决方案。 - user317033

4

更加简洁的方法是使用CompositeListener模式。

引用自: 如何为一个事件设置多个监听器?

您需要在项目中添加此类:

/**
 * Aux class to collect multiple click listeners.
 */
class CompositeListener implements OnClickListener {
    private List<OnClickListener> registeredListeners = new ArrayList<OnClickListener>();

    public void registerListener (OnClickListener listener) {
        registeredListeners.add(listener);
    }

    @Override
    public void onClick(View v) {

        for(OnClickListener listener:registeredListeners) {
            listener.onClick(View v);
        }
    }
}

然后在您的 MyCheckButton 上添加此内容。
private CompositeListener clickListener = new CompositeListener();

public MyCheckButton()
{
    super.setOnClickListener(clickListener); //multi event listener initialization
}

@Override
public void setOnClickListener(OnClickListener l) {
    clickListener.registerListener(l);
}

你所调用的 setOnClickListener 方法都将通过这个重载方法进行处理,添加到列表中并在事件触发时被调用。希望对你有所帮助。

1

由于在Android 2.1上只有一个OnclickListener可以工作(我不清楚后续版本),因此将视图设置为私有和静态,并创建一个静态函数来更改它,例如:

public class ExampleActivity extends Activity{

private SomeOtherclass someOtherClass;
private static Button b_replay;

 public void onCreate(Bundle savedInstanceState){
     someOtherClass = new SomeOtherclass();

   b_replay = (Button) findViewById(R.id.b_replay);
   b_replay.setOnClickListener(someOtherClass);
 }

 public static void changeReplayText(String text){
   b_replay.setText(text);
 }

}


1

由于每个视图只能有一个 onClickListener,所以我认为我需要定义一个接口:

public interface MyOnClickListener {
    public void onMyClick(View v);
}

从我的activity中实现它并覆盖onMyClick函数以执行我想要的操作,在MyCheckButton类中,我需要在构造函数中传递一个MyOnClickListener,保存它并在onClick处理程序内调用listener.onMyClick。

如果有更好的方法,请让我知道。我考虑在activity或MyCheckButton类中使用onTouch处理程序,但稍后如果我在其中一个上添加onTouch或onClick,我将会遇到难以注意到的错误。

我的想法不起作用,因为我不知道如何从我的构造函数中获取对活动的引用:

public class TVCheckButton extends TextView {

    private MyOnClickListener mListener;

    public TVCheckButton(Context context, AttributeSet attrs) {
        super(context, attrs);

        mListener = ???;
    }
}

这不起作用是因为我无法/不知道如何在xml中实例化MyCheckButton视图时向MyCheckButton类添加参数。你能将Context参数转换为你的活动吗? - user317033

0
在第一节课中,定义一个虚拟按钮:
private static Button myVirtualButton = new Button(context);

...以及一个公共方法来注册它:

public static void registerMyVirtualButton(Button b) { myVirtualButton = b;}

OnClickListener 中执行所需的任何操作,最后软点击虚拟按钮:
if (myVirtualButton!=null) { myVirtualButton.callOnClick(); }

在第二个类中,定义一个按钮及其OnClickListener,并添加任何其他所需的操作。
通过registerMyVirtualButton将按钮传递给第一个类。 在单击第一个类的对象时,将执行两个操作。

0

0
由于某些原因,我无法使用上面的答案,所以这里提供一种替代方法: //我将所有内容放在一个方法中,其中有两个按钮,根据外部因素,一个按钮会显示,另一个则不会,也就是“消失”。所以,我已经检查过了!希望能对某些人有所帮助!!
Button b = (Button) findViewById(R.id.b_reset);
Button breakk = (Button) findViewById(R.id.b_break);

    if ((findViewById(R.id.b_reset)).getVisibility() == View.VISIBLE) {
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

//一些代码和方法...

            }
        });
    } else if ((findViewById(R.id.b_break)).getVisibility() == View.VISIBLE) {

        breakk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

//一些代码和方法...

            }
        });
    }

-3
您可以通过以下方式将OnClick监听器附加到按钮:
Button button= (Button) findViewById(R.id.button1);
    button.setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v) {
          // do something
      }

    });

同样地,你的TextView应该有它自己的OnClick监听器。

我的问题是有两个OnClickListeners和一个“button”,其中我的按钮是我扩展的TextView。 - user317033
一个视图上不能有两个clickListeners。 - Falmarri
我不知道为什么其他所有的UI系统都支持多个事件处理程序,因此我将这个问题标记为“事件冒泡”。 - user317033

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