UIButton with multiple actions: How to prevent oth

2020-03-26 07:03发布

I'm trying to find a way to consume a button press, not from the response chain per se, but from other action methods bound to that button. I've looked all over for this solution and have been unable to find it.

For example, lets say I set up a button with a selector for an event:

[button addTarget:self action:@selector(handler1:) forControlEvents:UIControlEventTouchUpInside];

Then later in the code, based on specific app circumstances I want to add another event handler for the same control event to the same button:

[button addTarget:self action:@selector(handler2:) forControlEvents:UIControlEventTouchUpInside];

This works fine, both events are indeed called. But my question is, without removing handler1 from the button, how can I make it so that when handler2 is called, the event is "consumed" and handler1 does not get called?

The reason I have such a circumstance is that I want my app to go into a tutorial mode, where I dynamically bind new events to buttons while in the tutorial mode. The tutorial will instruct the user to tap a certain button, but I want the tap events on the other buttons on the screen to be ignored, basically forcing the user to tap the requested button to continue with the tutorial. So every button gets a new TouchUpInside handler added when the user enters the tutorial. I want this new handler to be called first and block the original handler from executing.

I have been able to achieve it being called first by getting all the original events in an NSSet, then calling [button removeTarget...] for all the existing events. Then I add my dynamic event and then re-add all the original events from the set. This works in the debugger to show that my dynamic event is indeed called first.

  • For example:
  • handler1 will do something when pressed (default handler for the button)
  • handler2 is added dynamically and will communicate with the tutorial controller, "consuming" the tap event (preventing handler1 from executing).

When not in tutorial mode, I want handler1 to still do what it's supposed to do, but if handler2 exists I want that method to run, then prevent handler1 from being called. I can't lose handler1 from the button because when the tutorial ends, I'd want the app to work as intended. In addition, I may have certain cases where I still want handler1 to be called.

So, is it possible to consume an event and keep other related events from firing?

I have tried doing a [button resignFirstResponder] in handler2, but that doesn't seem to work. It still calls the original button event handler.

3条回答
姐就是有狂的资本
2楼-- · 2020-03-26 07:39

You may be able to add a category to UIButton (or subclass it), overriding the method sendActionsForControlEvents: to only call sendAction:to:forEvent: for one target (refer to the documentation on UIControl for descriptions of those methods).

查看更多
乱世女痞
3楼-- · 2020-03-26 07:43

if you know the current state of the app like tutorial etc then probably better to use only one handler1. And add to the body of the method handler1: if (mode == tutorial) {tutorial} else {default}.

查看更多
虎瘦雄心在
4楼-- · 2020-03-26 07:46

Based on the @danielquokka idea about override the method sendActionsForControlEvents:, I subclass UIButton and add following codes. It works fine. After firing event, it will block UI events for 0.5 seconds.

- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
    [super sendAction:action to:target forEvent:event];
    self.userInteractionEnabled = NO;

    ///! After handle UIEvent, block this button UI events for a while.
    [self performSelector:@selector(delayEnable) withObject:nil afterDelay:0.5];
}

- (void)delayEnable
{
    self.userInteractionEnabled = YES;
}

UPDATE

Another way to ignore UI events is by [[UIApplication sharedApplication] beginIgnoringInteractionEvents] and [[UIApplication sharedApplication] endIgnoringInteractionEvents].

beginIgnoringInteractionEvents and endIgnoringInteractionEvents will block all touch events for the Application until endIgnoringInteractionEvents called.

查看更多
登录 后发表回答