具有多个动作的 UIButton:如何防止其他动作触发

Posted

技术标签:

【中文标题】具有多个动作的 UIButton:如何防止其他动作触发【英文标题】:UIButton with multiple actions: How to prevent other actions from firing 【发布时间】:2014-10-02 21:13:45 【问题描述】:

我正在尝试找到一种方法来使用按钮按下,而不是来自响应链本身,而是来自绑定到该按钮的其他操作方法。我已经到处寻找这个解决方案,但一直找不到。

例如,假设我为一个事件设置了一个带有选择器的按钮:

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

然后在后面的代码中,根据具体的应用情况,我想为同一个按钮添加另一个事件处理程序,用于同一个控件事件:

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

这很好用,这两个事件都确实被调用了。但我的问题是,在不从按钮中删除 handler1 的情况下,我怎样才能使它在调用 handler2 时,事件被“消耗”并且 handler1 不会被调用?

我遇到这种情况的原因是我希望我的应用程序进入教程模式,在教程模式下我动态地将新事件绑定到按钮。本教程将指示用户点击某个按钮,但我希​​望忽略屏幕上其他按钮上的点击事件,基本上是强制用户点击请求的按钮以继续教程。因此,当用户进入教程时,每个按钮都会添加一个新的 TouchUpInside 处理程序。我希望首先调用这个新的处理程序并阻止原始处理程序执行。

我已经能够通过在NSSet 中获取所有原始事件来实现它,然后为所有现有事件调用[button removeTarget...]。然后我添加我的动态事件,然后重新添加集合中的所有原始事件。这在调试器中起作用,表明我的动态事件确实首先被调用。

例如: handler1 在按下时会做一些事情(按钮的默认处理程序) handler2 是动态添加的,它将与教程控制器通信,“消耗”点击事件(阻止 handler1 执行)。

当不在教程模式下时,我希望 handler1 仍然做它应该做的事情,但如果 handler2 存在,我希望该方法运行,然后阻止 handler1 被调用。我不能从按钮中丢失 handler1,因为当教程结束时,我希望应用程序按预期工作。此外,我可能在某些情况下仍希望调用 handler1。

那么,是否可以消费一个事件并阻止其他相关事件触发?

我尝试在 handler2 中执行 [button resignFirstResponder],但这似乎不起作用。它仍然调用原来的按钮事件处理程序。

【问题讨论】:

按钮教程功能完成后,为什么不能只重置第一个处理程序? UIButton remove all target-actions的可能重复 该应用有几十个按钮。也许屏幕上只有一两个人甚至会参与到教程中。如果用户按下任何不涉及的按钮,我不希望他们做他们默认应该做的事情。但如果我只是删除处理程序,我必须在某个地方跟踪所有处理程序,然后在教程结束时将它们添加回来。我可以这样做,但正在寻找更优雅的解决方案。如果做不到,那我就只能选择蛮力技术了。 :) 感谢您的回复。 另一种选择是一个不可见的按钮,它覆盖了可以实现教程功能的常规按钮。 对不起,这不是重复的。我不想从按钮中删除目标操作。问题是,我想向按钮添加一个新目标,并且只调用那个目标,直到我手动删除该目标操作。谢谢。 【参考方案1】:

基于@danielquokka关于重写方法sendActionsForControlEvents:的想法,我继承了UIButton并添加了以下代码。它工作正常。触发事件后,会阻塞 UI 事件 0.5 秒。

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

更新

另一种忽略 UI 事件的方法是 [[UIApplication sharedApplication] beginIgnoringInteractionEvents][[UIApplication sharedApplication] endIgnoringInteractionEvents]

beginIgnoringInteractionEventsendIgnoringInteractionEvents 将阻止应用程序的所有触摸事件,直到调用 endIgnoringInteractionEvents

【讨论】:

如此简单,却又如此有效。【参考方案2】:

如果您知道教程等应用程序的当前状态,那么最好只使用一个处理程序1。并添加到方法 handler1 的主体: if (mode == tutorial) tutorial else default。

【讨论】:

我认为这不是一个好的解决方案;这个很少使用的代码不需要出现在主处理程序中。它只会让事情变得更难阅读和维护。 我可以这样做,但这个特殊的应用程序是一个复杂的规则计算器(用于比赛评判)。它有多个屏幕,每个屏幕上有几十个按钮(这就是我们需要教程的原因)。这将需要我进行大量修改,而这些修改可以通过更优雅的高级解决方案来避免。我很欣赏这个建议,如果这个请求在 ios 框架中是不可能的,我最终会做类似的事情,但我想我会先在这里问是否有更好的方法来做到这一点。谢谢。 好的。那么您可能可以添加 GestureRecognizer 并使用方法 ...shouldReceiveTouch。并在此方法中检查它是否是您的按钮,然后返回 NO; (取消handler1),并在那个地方调用handler2。我没有对其进行测试,但它可以作为教程的单独解决方案。 感谢 kabarga,这是一个有趣的想法,可能完全符合我的要求。我会回来报告...【参考方案3】:

您可以为 UIButton 添加一个类别(或其子类),覆盖方法 sendActionsForControlEvents: 以仅为一个目标调用 sendAction:to:forEvent: (有关这些方法的描述,请参阅 UIControl 上的文档)。

【讨论】:

以上是关于具有多个动作的 UIButton:如何防止其他动作触发的主要内容,如果未能解决你的问题,请参考以下文章

如何将点击动作添加到自定义 UIButton?

如何使这个 UIButton 的动作正确运行?

如何将模型传递给具有其他参数的动作

具有多个“动作”的 HTML 表单

JSP MVC:如何使用具有多个视图和动作的控制器 [重复]

UIbutton 长按和 Touch Up 里面