Programmatically Adding UITapGestureRecognizer To UIViews in Outlet Collection - ios

I am working with a series of views stored in an outlet collection.
#IBOutlet var theViews: [UIView]!
In my viewDidLoad function I am looping over the collection of views during which I create a UITapGestureRecognizer and add it to the view.
for v in theViews {
let tap = UITapGestureRecognizer(target: self, action: #selector(self.flipSingleView(sender:)))
tap.delegate = self
tap.numberOfTapsRequired = 1
tap.numberOfTouchesRequired = 1
v.addGestureRecognizer(tap)
v.isUserInteractionEnabled = true
}
Here is the function that the selector points to:
#objc func flipSingleView(sender: UITapGestureRecognizer) {
print("tapped")
}
Additional notes:
User interaction is enabled for these views
Breakpoint inside flipSingleView is never reached
The View Controller implements UIGestureRecognizerDelegate (I've looked through the protocol and don't see a function that would be useful in this situation)
Have Verified that all views in question have outlet connections to the outlet collection
Nothing prints to the console

You mentioned your views are in an outlet collection, so I'm assuming it looks something like this:
#IBOutlet var myViews: [UIView]!
Not sure you need everything you threw in there. Try this:
// In viewDidLoad
myViews.forEach{ view in
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(gesture:)))
tap.numberOfTapsRequired = 1
tap.delegate = self
view.addGestureRecognizer(tap)
}
For your handler:
#objc func handleTap(gesture: UIGestureRecognizer) {
print("tap")
}
And lastly, put in a section for delegate methods, even if it's just empty:
extension ViewController: UIGestureRecognizerDelegate {
// TODO: Fill in as needed
}
To figure out which view sent it, you could add a tag to the view.

Related

Swift UIGestureRecognizer is not working / is not doing anything

I have a small issue that I couldn't fix for a few hours now! I have a simple ViewController with a label, which is linked to my ViewController class. I also set up an UIGestureRecognizer to change the text of the label when the label is clicked. But weirdly nothing happens at all.
The text of the label changes from whatever is set in the Storyboard to "Hello", so the setup is correct. But when I click the label, nothing happens.
Here's the entire ViewController class:
import UIKit
class PremiumViewController: UIViewController {
// Views
#IBOutlet weak var premiumLabel: UILabel!
// View Did Load
override func viewDidLoad() {
super.viewDidLoad()
premiumLabel.text = "Hello"
// Tap listener
let tap = UIGestureRecognizer(target: self, action: #selector(PremiumViewController.clicked))
premiumLabel.isUserInteractionEnabled = true
premiumLabel.addGestureRecognizer(tap)
}
#objc func clicked() {
premiumLabel.text = "You clicked me"
}
}
Use UITapGestureRecognizer instead of UIGestureRecognizer
change from
let tap = UIGestureRecognizer(target: self, action: #selector(PremiumViewController.clicked))
to
let tap = UITapGestureRecognizer(target: self, action: #selector(PremiumViewController.clicked))

UILabel set onClick

I'm building an application in Swift 3, so I want to call a function if I click on a particular UILabel, so I'm write this code but not works:
let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapFunction))
self.labelTemp.isUserInteractionEnabled = true
self.labelTemp.addGestureRecognizer(tap)
How can I render UILabel clickable ?
Set user interaction enabled for the UILabel and add the below code in the viewDidLoad()
self.label.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(self.labelTapped))
self.label.addGestureRecognizer(tap)
Add the tap action function as below :
#objc func labelTapped(_ gestureRecognizer: UITapGestureRecognizer) {
print("Label clicked")
}
Please make user that there is no other transparent view overlapping the UILabel in the view. If the UILabel is a part of another view then please make sure that the container View's user interaction is enabled.
Hope this helps.
Your selector should be an #objc func within self.
<#YourLabel#>.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.handleLabelTap)))
And when the user taps the label it will trigger:
#objc func handleLabelTap() {
// handle label tap here
}
You are lacking a function to trigger when the gesture touch is recognized. You need to add following:
let tap = UITapGestureRecognizer(target: self, action: #selector(tapFunction(_:)))
self.labelTemp.isUserInteractionEnabled = true
self.labelTemp.addGestureRecognizer(tap)
#objc func tapFunction(_ gestureRecognizer: UITapGestureRecognizer) {
// handle label tap here
}
Please ensure that You have connected the outlet to UILabel because I have created simple demo code by copy-paste your code and it is worked as expected.
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(tapFunction))
self.labelTemp.isUserInteractionEnabled = true
self.labelTemp.addGestureRecognizer(tap)
}
#objc func tapFunction() {
print("tapFunction")
}
I suggest, Please remove UILabel from UIViewController and add it again.
Download sample code
Note: - Please ensure that user-interaction of UILabelis enabled
First you need to add Tap Gesture into storyboard
Create Action of that particular gesture
override func viewDidLoad() {
super.viewDidLoad()
let tapOnLabel = UITapGestureRecognizer(target: self, action: #selector(self.tapGestireAction))
self.labelTemp.isUserInteractionEnabled = true
self.labelTemp.addGestureRecognizer(tapOnLabel)
}
#IBAction func tapGestureAction(_ sender: UITapGestureRecognizer) {
//Perform action
}

Triggering UITapGestureRecognizers from overlapping Views

I have one main view and 4 subviews of the mainview they all have their UITapGestureRecognizer, when I tap on one subview how can it be triggered both views. Example below,
if I tap to subview 1 desired log would be:
subview1 is clicked
MainView is clicked
My Code
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let mainGesture = UITapGestureRecognizer(target: self, action: #selector(mainGestureActivated))
self.view.addGestureRecognizer(mainGesture)
let subGesture = UITapGestureRecognizer(target: self, action: #selector(subViewGestureActivated))
self.subview1.addGestureRecognizer(subGesture)
}
#objc func mainGestureActivated(){
print("MainView Clicked")
}
#objc func subViewGestureActivated(){
print("Subview Clicked")
}
it prints only subview clicked! Is it possible to trigger both gestureRecognizers since main is encapsulating other.
First you should conform to UIGestureRecognizerDelegate in your VC, and then implement the delegate func of shouldRecognizeSimultaneouslyWith. Inside the function, you should detect if the gestureRecognizer, and the otherGestureRecognizer are the wants you want, and if so, you should allow them to work simultaneously,
Conform to delegate, and Declare gesture recognizers outside of viewDidLoad (because you need to access them in the delegate method later.)
var mainGestureRecognizer = UITapGestureRecognizer()
var subGestureRecognizer = UITapGestureRecognizer()
Initialize your recognizers, and set your VC as their delegate:
mainGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(mainGestureActivated))
subGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(subViewGestureActivated))
mainGestureRecognizer.delegate = self
subGestureRecognizer.delegate = self
Implement the delegate function mentioned above to allow simultaneous recognition for subView and mainView:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == subGestureRecognizer && otherGestureRecognizer == mainGestureRecognizer {
return true
}
return false
}
And if you want it to work for 4 different subviews, then you should check with else if statements inside the delegate method.

How to identify which subView has been pressed in Swift?

I have a built a UIView class called SetView. In its initializer I create multiple subviews and later in ViewController I want to determine which subView has been pressed. in my viewDidLoad method I iterate through all the subviews add them to a class array of UIView called mySubViews and it my getIndex method, I am trying to retrieve the value which is always retrieved as nil. I suppose that it is my main view that is passed as a sender rather than particular subviews but I don't know how to pass specific subviews since #selector does not accept argument. I would appreciate any suggestions on how I could determine which subview was pressed to update features of a given subview.
override func viewDidLoad() {
super.viewDidLoad()
for view in setView.subviews {
mySubViews.append(view)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(getIndex(_:)))
gestureRecognizer.delegate = self
view.addGestureRecognizer(gestureRecognizer)
}
}
#objc func getIndex(_ sender:UIView) {
print(mySubViews.index(of: sender))
}
The sender should be the gesture recognizer. Then give your views a tag and set the same tag for your gesture recognizer. Then you can get the view with viewWithTag.
Or with your array it could be like
override func viewDidLoad() {
super.viewDidLoad()
var index = 0
for view in setView.subviews {
mySubViews.append(view)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(getIndex(_:)))
gestureRecognizer.tag = index
gestureRecognizer.delegate = self
view.addGestureRecognizer(gestureRecognizer)
index += 1
}
}
#objc func getIndex(_ sender: UITapGestureRecognizer) {
print(mySubViews[sender.tag])
}
The sender in your target method is a gesture recognizer. The fact that it is only interpreted as UIView will always return nil in your call.
Try the following:
#objc func getIndex(_ sender: UIGestureRecognizer) {
print(mySubViews.index(of: sender.view))
}
Still I would prefer you would use a single gesture recognizer on the super view. Then you can check the hit view by checking if the gesture recognizer was within the view bounds:
#objc func getIndex(_ sender: UIGestureRecognizer) {
let allViewsAtGestureLocation = mySubViews.filter { $0.bounds.contains(sender.location(in: $0)) }
let firstHitView = mySubViews.first(where: { $0.bounds.contains(sender.location(in: $0)) })
}
I assume you would need the second one. From it you can again find an index.
Maybe try something like this:
for view in setView.subviews {
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(getIndex(_:)))
gestureRecognizer.delegate = self
view.addGestureRecognizer(gestureRecognizer)
mySubViews.addSubview(view)
}
Don't use append if you're trying to add it in, and add it after you assign the gesture.

UITapGestureRecognizer on custom table view cell doesn't work

I'm trying to add a gesture recognizer for an image in a custom table view cell. For some reason I can't seem to make it work though. Here's my code
override func awakeFromNib() {
super.awakeFromNib()
heartImage.userInteractionEnabled = true
let gesture = UITapGestureRecognizer(target: self, action:Selector("onHeartTap"))
gesture.delegate = self
heartImage.addGestureRecognizer(gesture)
}
func onHeartTap(sender: UITapGestureRecognizer)
print("TAPPED")
}
The function awakeFromNib() gets called correctly, but onHeartTap() never gets called when tapping the image. What am I doing wrong?
User interaction was enabled for the image but not for the cell.
Enabled it for the cell from the storyboard and everything works. Thanks for the help everybody!
In your selector name 'onHeartTap' ":" is missing
just replace
let gesture = UITapGestureRecognizer(target: self, action:Selector("onHeartTap"))
with
let gesture = UITapGestureRecognizer(target: self, action:Selector("onHeartTap:"))
And also any specific reason you are doing this in awakeFromNib?? You can do this on viewWillAppear also.
I had a similar problem, that a UIImageView in a UITableViewCell subclass would not trigger the gesture recognizer that I set up.
func viewDidLoad() {
imageView.addGestureRecognizer(UIGestureRecognizer(target: self, action: #selector(imageViewTapped(sender:))))
imageView.isUserInteractionEnabled = true
}
the problem was the viewDidLoad() is not called for UITableViewCell:
Can I use viewDidLoad method in UITableviewCell?
set the gesture recognizer in awakeFromNib() instead:
override func awakeFromNib() {
imageView.addGestureRecognizer(UIGestureRecognizer(target: self, action: #selector(imageViewTapped(sender:))))
imageView.isUserInteractionEnabled = true
}

Resources