4

what i want to achieve is when user touch on UIImageView set Image1, when user lifts his finger set Image2.

i can only get UIGestureRecognizerState.Ended with this code

var tap = UITapGestureRecognizer(target: self, action: Selector("tappedMe:"))     
imageView.addGestureRecognizer(tap)
imageView.userInteractionEnabled = true
   
func tappedMe(gesture: UITapGestureRecognizer)
{
    
    if gesture.state == UIGestureRecognizerState.Began{
        imageView.image=originalImage
        dbgView.text="Began"
    }else if  gesture.state == UIGestureRecognizerState.Ended{
        imageView.image=filteredImage
        dbgView.text="Ended"
    }else if  gesture.state == UIGestureRecognizerState.Cancelled{
        imageView.image=filteredImage
        dbgView.text="Cancelled"
    }else if  gesture.state == UIGestureRecognizerState.Changed{
        imageView.image=filteredImage
        dbgView.text="Changed"
    }

}
H4SN
  • 1,482
  • 3
  • 24
  • 43

3 Answers3

5

The UITapGestureRecognizer doesn't change it's state to .Began, but the UILongPressGestureRecognizer does. If you for some reason font want to override the touch callbacks directly you could use a UILongPressGestureRecognizer with a very short minimumPressDuration of like 0.1 to achieve the effect.

Example by @Daij-Djan:

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view, typically from a nib.

    var tap = UILongPressGestureRecognizer(target: self, action: Selector("pressedMe:"))
    tap.minimumPressDuration = 0
    self.view.addGestureRecognizer(tap)
    self.view.userInteractionEnabled = true
  }

  func pressedMe(gesture: UITapGestureRecognizer) {
    if gesture.state == .Began{
      self.view.backgroundColor = UIColor.blackColor()
    } else if  gesture.state == .Ended {
      self.view.backgroundColor = UIColor.whiteColor()
    }
  }
}
kiecodes
  • 1,642
  • 14
  • 28
  • upvoted this, because subclassing the imageView for this would be overkill – Daij-Djan Dec 07 '15 at 11:26
  • @Daij-Djan IMO Adding event-listeners is more overkill than subclassing. – Sentry.co Aug 06 '18 at 14:28
  • @eonist Subclassing has a lot of other problems you want to avoid. – kiecodes Aug 08 '18 at 05:50
  • @Kie IMO Subclassing has it's pros and cons, and managing event listeners has it's pros and cons. An argument can be made that using subclassing and letting apple add/remove listeners isn't such a bad idea. – Sentry.co Aug 08 '18 at 17:33
4

Here is the solution:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        if touch.view == self {
            //began
        }
    }
    super.touchesBegan(touches, with: event)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        if touch.view == self {
            //end
        }
    }
    super.touchesEnded(touches, with: event)
}

Note: Put this inside a UIView SubClass and add: userInteractionEnabled = true inside the init block

Josselin
  • 2,593
  • 2
  • 22
  • 35
H4SN
  • 1,482
  • 3
  • 24
  • 43
  • 1
    downvoted this, because you provide no explanation and only some random piece of code that isn't even just 1 block ;) -- make it nicer [subclassing the imageView for this is overkill if the UILongPressGestureRecognizer works fine] – Daij-Djan Dec 07 '15 at 11:29
  • This solution is nice because it keeps the parent view scrollable – Josselin Jul 20 '21 at 12:26
1

The best and most practical solution would be to embed your UIImageView within a UIControl subclass.

By default UIImageView has user interaction enabled. If you create a simple UIControl subclass you can easily add your image view into it and then use the following methods to achieve what you want:

let control = CustomImageControl()
control.addTarget(self, action: "imageTouchedDown:", forControlEvents: .TouchDown)
control.addTarget(self, action: "imageTouchedUp:", forControlEvents: [ .TouchUpInside, .TouchUpOutside ])

The advantages of doing it this way is that you get access to all of the different touch events saving you time from having to detect them yourself.

Depending on what you want to do, you could also override var highlighted: Bool or var selected: Bool to detect when the user is interacting with the image.
It's better to do it this way so that your user has a consistent user experience with all the controls in their app.

A simple implementation would look something like this:

final class CustomImageControl: UIControl {

    let imageView: UIImageView = UIImageView()

    override init(frame: CGRect) {
        super.init(frame: frame)

        // setup our image view
        imageView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(imageView)
        imageView.leadingAnchor.constraintEqualToAnchor(leadingAnchor).active = true
        imageView.trailingAnchor.constraintEqualToAnchor(trailingAnchor).active = true
        imageView.topAnchor.constraintEqualToAnchor(topAnchor).active = true
        imageView.bottomAnchor.constraintEqualToAnchor(bottomAnchor).active = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

final class MyViewController: UIViewController {


    override func viewDidLoad() {
        super.viewDidLoad()

        let control = CustomImageControl()
        control.translatesAutoresizingMaskIntoConstraints = false
        control.imageView.image = ... // set your image here.
        control.addTarget(self, action: "imageTouchedDown:", forControlEvents: .TouchDown)
        control.addTarget(self, action: "imageTouchedUp:", forControlEvents: [ .TouchUpInside, .TouchUpOutside ])

        view.addSubview(control)
        control.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
        control.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor).active = true
    }

    @objc func imageTouchedDown(control: CustomImageControl) {
        // pressed down on the image
    }

    @objc func imageTouchedUp(control: CustomImageControl) {
        // released their finger off the image
    }
}
liamnichols
  • 12,419
  • 2
  • 43
  • 62