118

How can I add UIView touchbegin action or touchend action programmatically as Xcode is not providing from Main.storyboard?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
dhaval shah
  • 4,499
  • 10
  • 29
  • 42
  • 2
    That one is for button, the OP wants to add event for UIView – Miknash May 28 '15 at 11:29
  • 1
    Use a `UILongPressGestureRecognizer` with the `minimumPressDuration` set to zero. [See this answer.](http://stackoverflow.com/a/38143429/3681880) It doesn't require subclassing or overriding anything. – Suragch Jul 01 '16 at 11:02

11 Answers11

170

You will have to add it through code. First, create the view and add it to the hierarchy:

var myView = UIView(frame: CGRectMake(100, 100, 100, 100))
self.view.addSubview(myView) 

After that initialize gesture recognizer. Until Swift 2:

let gesture = UITapGestureRecognizer(target: self, action: "someAction:")

After Swift 2:

let gesture = UITapGestureRecognizer(target: self, action:  #selector (self.someAction (_:)))

Then bind it to the view:

self.myView.addGestureRecognizer(gesture)

    

Swift 3:

func someAction(_ sender:UITapGestureRecognizer){     
  // do other task
}
    

Swift 4 just add @objc before func:

@objc func someAction(_ sender:UITapGestureRecognizer){     
    // do other task
}

Swift UI:

Text("Tap me!").tapAction {
    print("Tapped!")
}
Filip Culig
  • 128
  • 1
  • 11
Miknash
  • 7,888
  • 3
  • 34
  • 46
  • 1
    I have did that it is giving me an error when i click on the uiView. My code: let gesture = UITapGestureRecognizer(target: self.uiPendingView, action: "touchPending") self.uiPendingView.addGestureRecognizer(gesture) and method: func touchPending(sender: AnyObject) { println("METHOD>>>>>>>>>>>>>>>>>") } – dhaval shah May 28 '15 at 11:44
  • 1
    just add : in "touchPending:" ans in function it look like func touchPending(sender: UITapGestureRecognizer) – Rizwan Shaikh May 28 '15 at 11:51
  • 1
    you are missing ':' in action. – Miknash May 28 '15 at 12:07
  • Hi, How can I distinguish which UIView got clicked when they all have the same someAction function? – C Williams Mar 09 '19 at 16:31
  • Easiest way would be to use tag property and then in function determine which view is sender – Miknash Mar 09 '19 at 17:03
  • Furthermore you can design a custom view xib and then bind it into the touch event. But it depends on your requirement. [Here] (https://stackoverflow.com/questions/27371194/set-action-listener-programmatically-in-swift) – Wimukthi Rajapaksha Feb 12 '20 at 12:34
103

Swift 4 / 5:

let gesture = UITapGestureRecognizer(target: self, action:  #selector(self.checkAction))
self.myView.addGestureRecognizer(gesture)

@objc func checkAction(sender : UITapGestureRecognizer) {
    // Do what you want
}

Swift 3:

let gesture = UITapGestureRecognizer(target: self, action:  #selector(self.checkAction(sender:)))
self.myView.addGestureRecognizer(gesture)

func checkAction(sender : UITapGestureRecognizer) {
    // Do what you want
}
ventuz
  • 1,121
  • 1
  • 7
  • 9
26

Updating @Crashalot's answer for Swift 3.x:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.location(in: self)
        // do something with your currentPoint
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.location(in: self)
        // do something with your currentPoint
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.location(in: self)
        // do something with your currentPoint
    }
}
stevo.mit
  • 4,681
  • 4
  • 37
  • 47
19

Updating @Chackle's answer for Swift 2.x:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.locationInView(self)
        // do something with your currentPoint
    }
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.locationInView(self)
        // do something with your currentPoint
    }
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.locationInView(self)
        // do something with your currentPoint
    }
}
Crashalot
  • 33,605
  • 61
  • 269
  • 439
9

Put this in your UIView subclass (it's easiest if you make a sublcass for this functionality).

class YourView: UIView {

  //Define your initialisers here

  override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    if let touch = touches.first as? UITouch {
      let currentPoint = touch.locationInView(self)
      // do something with your currentPoint
    }
  }

  override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
    if let touch = touches.first as? UITouch {
      let currentPoint = touch.locationInView(self)
      // do something with your currentPoint
    }
  }

  override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
    if let touch = touches.first as? UITouch {
      let currentPoint = touch.locationInView(self)
      // do something with your currentPoint
    }
  }
}
Chackle
  • 2,249
  • 18
  • 34
  • @Chacle, I have more than 10 Uiview in my page, and i want to add action in some of Sub UIView. So for that what should i change? – dhaval shah May 28 '15 at 11:42
  • It depends what you want to use it for. Do you want to tell which `UIView` you press or do you want to handle some presses in each of the `UIView`? – Chackle May 28 '15 at 11:44
  • I want touchevent for some specifi UIview only. – dhaval shah May 28 '15 at 11:45
9

For swift 4

@IBOutlet weak var someView: UIView!  
let gesture = UITapGestureRecognizer(target: self, action:  #selector (self.someAction (_:)))
self.someView.addGestureRecognizer(gesture)

@objc func someAction(_ sender:UITapGestureRecognizer){
    print("view was clicked")
}
DevB2F
  • 4,674
  • 4
  • 36
  • 60
9

Create outlets from views that were created in StoryBoard.

@IBOutlet weak var redView: UIView!
@IBOutlet weak var orangeView: UIView!
@IBOutlet weak var greenView: UIView!   

Override the touchesBegan method. There are 2 options, everyone can determine which one is better for him.

  1. Detect touch in special view.

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
         if let touch = touches.first {
            if touch.view == self.redView {
                tapOnredViewTapped()
            } else if touch.view == self.orangeView {
                orangeViewTapped()
            } else if touch.view == self.greenView {
                greenViewTapped()
            } else {
                return
            }
        }
    
    }
    
  2. Detect touch point on special view.

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            let location = touch.location(in: view)
            if redView.frame.contains(location) {
                redViewTapped()
            } else if orangeView.frame.contains(location) {
                orangeViewTapped()
            } else if greenView.frame.contains(location) {
                greenViewTapped()
            }
        }
    
    }
    

Lastly, you need to declare the functions that will be called, depending on which view the user clicked.

func redViewTapped() {
    print("redViewTapped")
}

func orangeViewTapped() {
    print("orangeViewTapped")
}

func greenViewTapped() {
    print("greenViewTapped")
}
iAleksandr
  • 595
  • 10
  • 11
  • Very well great example thanks to showing me!! that we can also do this using touchEvent .. i know only two way button and gesture.. Thanks +1 – Yogesh Patel Jan 30 '20 at 07:06
  • by the way, this touch will not work in simulator. so if you're working on simulator, you can't test the code. – Keval Langalia Mar 25 '21 at 20:05
6

You can use this way; create an extension.

extension UIView {
    
    func addTapGesture(action : @escaping ()->Void ){
        let tap = MyTapGestureRecognizer(target: self , action: #selector(self.handleTap(_:)))
        tap.action = action
        tap.numberOfTapsRequired = 1
        
        self.addGestureRecognizer(tap)
        self.isUserInteractionEnabled = true
        
    }
    @objc func handleTap(_ sender: MyTapGestureRecognizer) {
        sender.action!()
    }
}

class MyTapGestureRecognizer: UITapGestureRecognizer {
    var action : (()->Void)? = nil
}

and use this way:

@IBOutlet weak var testView: UIView!
testView.addTapGesture{
   // ...
}
    
Codetard
  • 2,441
  • 28
  • 34
Rasoul Miri
  • 11,234
  • 1
  • 68
  • 78
6

Swift 4.2:

@IBOutlet weak var viewLabel1: UIView!
@IBOutlet weak var viewLabel2: UIView!
  override func viewDidLoad() {
    super.viewDidLoad()

    let myView = UITapGestureRecognizer(target: self, action: #selector(someAction(_:)))
    self.viewLabel1.addGestureRecognizer(myView)
}

 @objc func someAction(_ sender:UITapGestureRecognizer){
   viewLabel2.isHidden = true
 }
Hiền Đỗ
  • 526
  • 6
  • 14
2

Just an update to above answers :

If you want to have see changes in the click event, i.e. Color of your UIVIew shud change whenever user clicks the UIView then make changes as below...

class ClickableUIView: UIView {
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            if let touch = touches.first {
                let currentPoint = touch.locationInView(self)
                // do something with your currentPoint
            }

            self.backgroundColor = UIColor.magentaColor()//Color when UIView is clicked.
        }

        override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
            if let touch = touches.first {
                let currentPoint = touch.locationInView(self)
                // do something with your currentPoint
            }

            self.backgroundColor = UIColor.magentaColor()//Color when UIView is clicked.
        }

        override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
            if let touch = touches.first {
                let currentPoint = touch.locationInView(self)
                // do something with your currentPoint
            }

            self.backgroundColor = UIColor.whiteColor()//Color when UIView is not clicked.

}//class closes here

Also, call this Class from Storyboard & ViewController as:

@IBOutlet weak var panVerificationUIView:ClickableUIView!
Pawan
  • 533
  • 1
  • 7
  • 31
2

Updating @stevo.mit's answer for Swift 4.x:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.location(in: self.view)
        // do something with your currentPoint
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.location(in: self.view)
        // do something with your currentPoint
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let currentPoint = touch.location(in: self.view)
        // do something with your currentPoint
    }
}
Jacob Ahlberg
  • 2,352
  • 6
  • 22
  • 44