开发者

Android - Two onClick listeners and one button

I have a custom TextView which is clickable. It defines its own onClick handler in order to change its a开发者_JAVA百科ppearance based on clicks. However if I then define a second onClick handler in my activity in order to do something based on the button being clicked, only one of the onClick functions is called. onClick is a void function - is there any way to say I didn't process this click, please pass it on to other onClick handlers?

To be more clear here is the code:

Inside MyCheckButton which extends TextView I have:

    setOnClickListener( mClickListener );

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

However I include MyCheckButton into my Activity, and of course I need to do something when its clicked so I attach another OnClickListener to it:

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

});

By calling setOnClickListener twice it appears that I am replacing the original listener so toggle() which changes the appearance is never called. How can I do something in my activity when this button is clicked if it is already using the onClick handler to change its appearance? I thought I would simply see both OnClickListeners getting called.


This is a bit dirty, but the way I would do this if you need multiple listeners is to register one that knows about the other. The first one (the one that's actually registered) will then need to know when to delegate to the other listener based on the conditions of the event. Actually, in reality, there's no real need to have two OnClickListener classes. The second class can implement whatever interface you want. Additionally, there's no need to create a special interface for what you need.

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

Then, in your code for your activity, you would do this

MyClickListener lstn = new MyClickListener();
mCheckBox.setOnClickListener(lstn);

Is there a reason this wouldn't work for you?

Alternatively, if you wanted, the second class could also implement the OnClickListener interface.

Additionally, if you need true bubbling, you could define your own interface that supports adding multiple click listeners to an intermediate class that happens to implement the OnClickListener interface. From there, in that class's onClick() method, you would iterate through the registered listeners calling the appropriate method.


A cleaner approach would be to use the CompositeListener pattern.

Taken from: how can I set up multiple listeners for one event?

You'd have to add this class in your project:

/**
 * 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);
        }
    }
}

Then add this on your MyCheckButton

private CompositeListener clickListener = new CompositeListener();

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

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

Both your calls to setOnClickListener would go through this override, get added to the list and get called when the event is fired. Hope it helps.


Since it appears I can only have one onClickListener per View. What I think I have to do is define an interface:

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

Implement it from my activity and override the onMyClick function to do whatever I want and in the MyCheckButton class I'll need to pass a MyOnClickListener in the constructor save it and call listener.onMyClick inside the onClick handler.

Let me know if theres a better way. I considered using the onTouch handler in either the activity or the MyCheckButton class, but later if I add onTouch or onClick to either one I will get a difficult to notice bug.

My idea doesn't work because I don't know how to get a reference to the activity from my constructor:

public class TVCheckButton extends TextView {

    private MyOnClickListener mListener;

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

        mListener = ???;
    }
}


Since only one OnclickListener works on Android 2.1 [I don't know about later versions) make the view private and static and create a static function that can change it e.g.

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

}


A nice generic approach is to use a list of listeners, such as ListenerList and WeakListenerList from the Beryl library.


For some reason I could not use the answers above so here is an alternative: //I had all of this in one method where I had two buttons, and based on external factors one would be visible and other would not aka 'gone'. So, I had that checked out! Hope it helps someone!!

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

//some code and methods...

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

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

//some code and methods...

            }
        });
    }


In the first class, define a virtual button:

private static Button myVirtualButton = new Button(context);

... and a public method to register it:

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

In the OnClickListener do whatever action is desired, and in the end, softclick the virtual button:

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

In the second class, define a button and its OnClickListener with whatever action is additionally desired.

Transmit the button to the first class via registerMyVirtualButton. Upon clicking the object of the first class, both actions will be executed.


You can attach an OnClick listener to the button in the following way :

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

    });

Similarily, your TextView should have it's on OnClick listener.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜