自定义 UIControl,动作调用两次

Posted

技术标签:

【中文标题】自定义 UIControl,动作调用两次【英文标题】:Custom UIControl, action called twice 【发布时间】:2016-04-14 15:39:41 【问题描述】:

我正在尝试创建 UIControl 的子类并跟踪触摸以更改控件外观。

我不知道为什么,但是如果我从 IB 或代码添加操作(用于 .TouchUpInside),当我触摸控件时,注册操作方法会被调用两次。 堆栈跟踪告诉我第一个调用来自_sendActionsForEvents:withEvent:,第二个不清楚。 以下是我如何覆盖跟踪方法:

 override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool 
        let touchPoint = touch.locationInView(self)
        if CGRectContainsPoint(bounds, touchPoint) 
            sendActionsForControlEvents(.TouchDragInside)
        
        else 
            sendActionsForControlEvents(.TouchDragOutside)
        
        return true
    


override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool 
    sendActionsForControlEvents(.TouchDown)
    return true


override func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?) 
    guard let tou = touch else  return 
    let touchPoint = tou.locationInView(self)
    if CGRectContainsPoint(bounds, touchPoint) 
        sendActionsForControlEvents(.TouchUpInside)
    
    else 
        sendActionsForControlEvents(.TouchUpOutside)
    


override func cancelTrackingWithEvent(event: UIEvent?) 
    sendActionsForControlEvents(.TouchCancel)

我也发现了这个answer,但它似乎不适合我的问题,因为当我为 .TouchUpInside 事件添加目标时,我没有从该答案中所述的事件调度程序自动获得任何操作.

【问题讨论】:

您是否在每个 sendActionsForControlEvents 上都设置了断点并查看是否有超过 1 个被击中?您是否为 touchDown 和一次 touchUpInside 触发了一个事件? 当然,我想我找到了答案。我稍后会发布它。基本上,似乎超类已经发送了动作,但我想追踪所有事件还是少数事件。所以我要发送一些已经发送的东西 【参考方案1】:

我发现我误解了文档,并且可能有很多人在那里(在互联网上看到一些示例)。 覆盖上述方法并不能让您管理事件分派,为此最好使用sendAction:to:forEvent:。 在我用UIControl 子类创建了一个小项目并为最流行的控制事件添加了一些操作之后,这些考虑出现了:

触地 内部修饰 在外面修饰 向外拖动 往里拖 值已更改

结果 除了值改变了,所有其他的事件都已经被调用了,甚至跟踪方法也被覆盖了。如果我们想发送一个改变的值,我们必须自己调用它,这是有道理的,因为它的名字与触摸无关。 我发现有趣的一件事是在调用外部跟踪时,它似乎是在用户将手指拖动到控件边界之外大约 50% 时调用的,我期待在通过它的边界之后立即

class TestControl: UIControl 
    override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool 
        let touchPoint = touch.locationInView(self)
        print(touchPoint)
        return true
    
    override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool 
        let touchPoint = touch.locationInView(self)
        print(touchPoint)

        return true
    

    override func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?) 
        guard let touch = touch else  return 
        let touchPoint = touch.locationInView(self)
        print(touchPoint)

    


class ViewController: UIViewController 

    @IBOutlet weak var tezst: TestControl!


    @IBAction func touchDown(sender: AnyObject)
        print("Touch Down")
    
    @IBAction func touchUpInside(sender: AnyObject)
        print("Touch up inside")
    

    @IBAction func touchUpOutside(sender: AnyObject)
        print("Touch up outside")
    
    @IBAction func touchDragOutside(sender: AnyObject)
        print("Touch drag outside")
    
    @IBAction func touchDragInside(sender: AnyObject)
        print("Touch drag inside")
    
    @IBAction func valueChanged(sender: AnyObject)
        print("Value changed")
    

【讨论】:

以上是关于自定义 UIControl,动作调用两次的主要内容,如果未能解决你的问题,请参考以下文章

检测触发 UIControl 动作的事件类型

突出显示 UIControl 子类

自定义 UIControl 总是发送 nil UIEvent 对象

如何实现自定义控件的目标动作机制?

53 记一次自定义 classloader 导致的 metadataspace OOM

53 记一次自定义 classloader 导致的 metadataspace OOM