自定义 UIButton 触发 IBAction 一次,然后再也不触发

Posted

技术标签:

【中文标题】自定义 UIButton 触发 IBAction 一次,然后再也不触发【英文标题】:Custom UIButton fires IBAction once, then never again 【发布时间】:2017-04-12 15:49:35 【问题描述】:

我有一个名为 RippleButton 的自定义 UIButton 声明如下

public class RippleButton: UIButton

基本上它在触摸时会产生涟漪效果。我将此自定义按钮与以下 IBAction 一起使用

@IBAction func toggleMic() 
    if isMicrophoneOn 
        print("Stopped recording")
        micIcon.image = UIImage(named: "mic_off")
        micLabel.text = "Start Recording"
     else 
        print("Started recording")
        micIcon.image = UIImage(named: "mic_on")
        micLabel.text = "End Recording"
    

    isMicrophoneOn = !isMicrophoneOn

通过 Touch Up Inside 事件的设计编辑器将操作分配给按钮。

我的 RippleButton 像这样覆盖 touchesBegan

override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
    super.touchesBegan(touches, with: event)
    ripple.animate(sender: self, location: touches.first!.location(in: self))

当我第一次触摸按钮时,它会触发 IBAction 并从我的类 Ripple 中播放我的动画

func animate(sender: UIView, location: CGPoint)        
    ripple?.transform = CGAffineTransform(scaleX: 1, y: 1)
    let size = Double(sender.bounds.width) > Double(sender.bounds.height) ? sender.bounds.width : sender.bounds.height
    ripple?.frame = CGRect(x: location.x - size / 2, y: location.y - size / 2, width: size, height: size)
    ripple?.layer.cornerRadius = size / 2.0
    ripple?.alpha = CGFloat(opacity)
    ripple?.backgroundColor = color
    ripple?.transform = CGAffineTransform(scaleX: 0, y: 0)
    container?.frame = CGRect(x: 0, y: 0, width: sender.frame.size.width, height: sender.frame.size.height)
    container?.layer.cornerRadius = sender.layer.cornerRadius
    container?.clipsToBounds = true

    UIView.animate(withDuration: TimeInterval(speed),
                   delay: 0.0,
                   options: .curveEaseOut,
                   animations: 
                    self.ripple?.transform = CGAffineTransform(scaleX: 2.5, y: 2.5)
                    self.ripple?.alpha = 0.0
    )

ripple是添加到container的子视图,container是添加到RippleButton的视图

当我在第一次触摸后触摸它时,动画会播放,但 IBAction 不会触发。为什么它会触发一次,然后再也不会触发?

【问题讨论】:

与其覆盖touchesBegan,不如直接在界面生成器中连接touchDown事件? 因为我不想对所有使用此类的按钮都这样做。因为我打算在多个地方使用这个类,所以每次我实现这个类时,都会在 IB 中连接touchDown 很多重复的工作。 如果你只使用UIButton 可以吗? 你有没有试过在ripple.annimation之后调用super.touchesBegan,这个按钮有很多神奇的作用 @Alistra 是的,调用 IBAction 时默认的 UIButton 可以正常工作 【参考方案1】:

您说“涟漪是添加到容器的子视图,容器是添加到 RippleButton 的视图”......您是在“涟漪”效果之后删除该容器吗?也许这就是触摸事件。

【讨论】:

这就是问题所在。我正在添加容器来填充按钮,然后拦截触摸。通过添加container?.isUserInteractionEnabled = false,我能够让事情按预期工作。【参考方案2】:

在 touchesEnded 中默认通过调用 self.sendActionsForControlEvents 触发动作。尝试覆盖 touchesEnded 和 touchesCancelled(使用超级调用)并在两者中设置断点。也许该活动将第二次取消。在这种情况下,您的动画会以某种方式干扰内部按钮状态的实现。这很难修复,因为 UIButton 是一个黑盒,更糟糕的是它的内部实现可能会改变。那么你应该从 UIControl 派生。

看看:4 different ways to handle tap

【讨论】:

很遗憾,此链接已损坏。

以上是关于自定义 UIButton 触发 IBAction 一次,然后再也不触发的主要内容,如果未能解决你的问题,请参考以下文章

在主视图控制器的自定义单元格中使用来自 UIButton 的 IBAction

UIButton click(IBAction)没有以编程方式触发

在 UITableViewCell 中为自定义 UIButton 设置动画

UIButton 和 IBAction

UIbutton不改变IBAction内的背景

将 IBAction 连接到自定义类