3

I'm trying to create a subclass of UIControl and track touches to change control appearance.

I don't know why but if I add the action (for .TouchUpInside) from IB or code, when I touch the control the register action method get called twice.
The stack trace tells me that me that the first call comes from _sendActionsForEvents:withEvent:, the second is not clear.
Here there is how I overridden track methods:

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

I've found also this answer but it doesn't seems to fit my issue, because when I add the target for .TouchUpInside event I don't get any action automatically from the event dispatcher as stated in that answer.

Community
  • 1
  • 1
Andrea
  • 26,120
  • 10
  • 85
  • 131
  • Did you put breakpoints on each of the sendActionsForControlEvents and see if more than 1 is being hit? Are you getting an event fired once for the touchDown and once for the touchUpInside? – fsb Apr 14 '16 at 16:26
  • Sure, I guess I've found the answer. I'll post it later. Basically it seems that action are already sent by superclass, but I want to track down if all events or just a few. So I'm sending something that is already sent – Andrea Apr 14 '16 at 17:06

1 Answers1

4

I've found that I misunderstood the documentation, and probably a lot of person out there (seeing some samples on internet).
Overriding the mentioned methods doesn't make you able to manage event dispatching, to do that it should be probably better use sendAction:to:forEvent:.
Those considerations comes after I made a little project with a UIControl subclass and add some actions for the most popular control events:

  • touch down
  • touch up inside
  • touch up outside
  • drag outside
  • drag inside
  • value changed

RESULTS
Except for value changed, all the other events are already called, even tracking methods are overriden. If we want to send a value changed we must call it by ourselves, and that makes sense because as per its name is not related to touches.
One thing that I've found interesting is when tracking outside is called, it seems to be called when the user drags the finger about 50% more outside the bounds of the control, I was expecting right after passing its bounds

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")
    }
}
Andrea
  • 26,120
  • 10
  • 85
  • 131