【问题标题】:Android - Two onClick listeners and one buttonAndroid - 两个 onClick 监听器和一个按钮
【发布时间】:2011-01-06 19:28:18
【问题描述】:

我有一个可点击的自定义 TextView。它定义了自己的 onClick 处理程序,以便根据点击更改其外观。但是,如果我随后在我的活动中定义第二个 onClick 处理程序以便根据被单击的按钮执行某些操作,则只会调用其中一个 onClick 函数。 onClick 是一个无效函数 - 有什么办法可以说我没有处理此点击,请将其传递给其他 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 处理程序更改其外观,我该如何在我的活动中执行某些操作?我以为我只会看到两个 OnClickListener 都被调用。

【问题讨论】:

  • 是的,我认为你是对的,你也可以尝试在你的 xml 文件中给它一个 onClick 属性,看看它是否仍然会在设置 onClickListener 后调用你的方法。
  • 我猜这不是事件冒泡问题,我的问题是你不能将两个 OnClickListeners 添加到同一个视图中???这是其他地方的标准做法,所以我很困惑。
  • 如果我使用 xml onClick,setOnClickListener 会覆盖它。

标签: android event-bubbling


【解决方案1】:

这有点脏,但如果您需要多个侦听器,我会这样做的方法是注册一个知道另一个侦听器的侦听器。第一个(实际注册的)然后需要知道什么时候根据事件的条件委托给另一个侦听器。实际上,实际上并没有必要拥有两个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 新手,所以它对我来说不是很明显。如果这种情况更频繁地发生,最后一个可能选项可能很有用。我也在考虑使用应用程序对象来注册监听器。
  • 这里的第一个建议可能是最干净最简单的解决方案。
【解决方案2】:

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

取自: how can I set up multiple listeners for one event?

你必须在你的项目中添加这个类:

/**
 * 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 的调用都将通过此覆盖,被添加到列表中并在事件触发时被调用。希望对您有所帮助。

【讨论】:

    【解决方案3】:

    因为看起来我每个视图只能有一个 onClickListener。我认为我要做的是定义一个接口:

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

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

    如果有更好的方法,请告诉我。我考虑在活动或 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 参数强制转换为您的活动吗?
    【解决方案4】:

    由于只有一个 OnclickListener 适用于 Android 2.1 [我不知道以后的版本如何] 将视图设为私有和静态并创建一个可以更改它的静态函数,例如

    公共类 ExampleActivity 扩展 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);
     }
    

    }

    【讨论】:

      【解决方案5】:

      一个很好的通用方法是使用侦听器列表,例如来自Beryl libraryListenerListWeakListenerList

      【讨论】:

        【解决方案6】:

        由于某种原因,我无法使用上面的答案,所以这里有一个替代方案: //我在一种方法中拥有所有这些,其中我有两个按钮,并且基于外部因素,一个是可见的,另一个不会又名“消失”。所以,我检查了!希望它可以帮助某人!

        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) {
        

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

                    }
                });
            }
        

        【讨论】:

          【解决方案7】:

          在第一个类中,定义一个虚拟按钮:

          private static Button myVirtualButton = new Button(context);
          

          ... 以及注册它的公共方法:

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

          OnClickListener 中做任何需要的操作,最后,软点击虚拟按钮:

          if (myVirtualButton!=null) { myVirtualButton.callOnClick(); }
          

          在第二个类中,定义一个按钮和它的OnClickListener 以及任何额外需要的操作。

          通过registerMyVirtualButton 将按钮传递给第一类。 单击第一个类的对象时,将执行两个动作。

          【讨论】:

            【解决方案8】:

            您可以通过以下方式将 OnClick 侦听器附加到按钮:

            Button button= (Button) findViewById(R.id.button1);
                button.setOnClickListener(new OnClickListener(){
                  @Override
                  public void onClick(View v) {
                      // do something
                  }
            
                });
            

            同样,您的 TextView 应该在 OnClick 监听器上。

            【讨论】:

            • 我的问题是两个 OnClickListener 和一个“按钮”,其中我的按钮是我扩展的 TextView。
            • 一个视图中不能有 2 个 clickListener。
            • 我想知道为什么因为所有其他 UI 系统都支持多个事件处理程序 - 因此我将此问题标记为“事件冒泡”
            猜你喜欢
            • 2014-04-25
            • 2012-02-04
            • 2014-06-06
            • 1970-01-01
            • 1970-01-01
            • 2011-11-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多