This question already has answers here:
Can you attach a UIGestureRecognizer to multiple views?
(12 answers)
Closed 5 years ago.
I have 2 UIImageView and a single tapGestureRecognizer.
override func viewDidLoad() {
// Do any additional setup after loading the view.
super.viewDidLoad()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(cameraTapped(tapGestureRecognizer:)))
cameraUIImageView.isUserInteractionEnabled = true
cameraUIImageView.addGestureRecognizer(tapGestureRecognizer)
plus1UIImageView.isUserInteractionEnabled = true
plus1UIImageView.addGestureRecognizer(tapGestureRecognizer)
//
}
I can only tap on the second UIImageView, which is plus1UIImageView.
Why?
A UIGestureRecognizer must be used with a single view only. You are using same object for both views. Try this.
override func viewDidLoad() {
// Do any additional setup after loading the view.
super.viewDidLoad()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(cameraTapped(tapGestureRecognizer:)))
cameraUIImageView.isUserInteractionEnabled = true
cameraUIImageView.addGestureRecognizer(tapGestureRecognizer)
let tapGestureRecognizer2 = UITapGestureRecognizer(target: self, action: #selector(cameraTapped(tapGestureRecognizer:)))
plus1UIImageView.isUserInteractionEnabled = true
plus1UIImageView.addGestureRecognizer(tapGestureRecognizer2)
}
You can only add a gesture recognizer to one view, so when you add it to the second it's getting removed from the first. More in depth answer here:
Can you attach a UIGestureRecognizer to multiple views?
As all ans stated you can only add a gesture recognizer to one view. Although if both of your imageviews in same super view you can add tap gesture to their superview and access its subviews. You can check for tapped subview and take reference of tapped imageview using hitTest: method. Check my previous ans here. Do let me know if you have any queries in comment.
Related
I have create an date component and have problems with the GestureRecognizer.
First line is a StackView with labels. If I attach a TapGestureRecognizer it is fired on touch. The following Lines are subviews in a Stackview consisting of a label and an image view. I can add the Recognizer to the subview, to the label or the image view. It never gets fired and I made sure that userInteraction is enabled.
What could be the problem?
Here an example how I add the recognizer:
func addTap(){
dayLabel.isUserInteractionEnabled = true
imageView.isUserInteractionEnabled = true
isUserInteractionEnabled = true
tap1 = UITapGestureRecognizer(target: self, action: #selector(handleTap(recognizer:)))
tap2 = UITapGestureRecognizer(target: self, action: #selector(handleTap(recognizer:)))
tap3 = UITapGestureRecognizer(target: self, action: #selector(handleTap(recognizer:)))
dayLabel.addGestureRecognizer(tap1!)
imageView.addGestureRecognizer(tap2!)
addGestureRecognizer(tap3!)
}
#objc func handleTap(recognizer: UITapGestureRecognizer){
logger.debug("tap")
changeSelection()
}
You can find a little demo project boiled down to the problem here: https://github.com/ogezue/datedemo
Problem I can see is your view must be cover with Image and label
and you are adding same UITapGestureRecognizer to all so that is added on last object say view (which is covered with image and label) so it may not able to get tap event
You need three different objects of UITapGestureRecognizer you can't add same tap gesture on different views
Hope it may solve your problem
For every view (Label/Imageview) you should create a tap object not the same one added to both . . .
I have two copies of a control (its called a RatingControl). How do I write handlers that can be invoked on the correct object when somebody double taps on them?
I have:
#IBOutlet weak var ratingControl: RatingControl!
#IBOutlet weak var ratingControl2: RatingControl!
inside a TableViewController and then
override func viewDidLoad() {
super.viewDidLoad()
let tapGR = UITapGestureRecognizer(target: ratingControl, action: #selector(RatingControl.doubleTap(_:)))
tapGR.numberOfTapsRequired = 2
self.view.addGestureRecognizer(tapGR)
let tapGR2 = UITapGestureRecognizer(target: ratingControl2, action: #selector(RatingControl.doubleTap(_:)))
tapGR2.numberOfTapsRequired = 2
self.view.addGestureRecognizer(tapGR2)
}
RatingControl.doubleTap(_) is an innocuous event handler.
When there is a double tap on the second rating control, the doubleTap method is called but is dispatched on the first rating control object!
I have tried setting two targets on a single UITapGestureRecognizer but it runs into the same problem.
Thanks much!
You need to add the gesture recognizers to the two rating controls instead of to self.view.
Try this:
let tapGR = UITapGestureRecognizer(target: self, action: #selector(RatingControl.doubleTap(_:)))
tapGR.numberOfTapsRequired = 2
ratingControl.addGestureRecognizer(tapGR) // ratingControl, not self.view
let tapGR2 = UITapGestureRecognizer(target: self, action: #selector(RatingControl.doubleTap(_:)))
tapGR2.numberOfTapsRequired = 2
ratingControl2.addGestureRecognizer(tapGR2) // ratingControl2, not self.view
There are 2 parts to hooking up a gesture recognizer: the target, which determines which object gets notified when the recognizer is triggered, and the view it's attached to, which determines from which view the recognizer recognizes the gesture.
You've got 2 gesture recognizes configured the same way, both attached to self.view. They are therefore going to respond to taps on self.view (which I assume is the view controller's content view.) I don't think it's clear which gesture recognizer is going to be triggered when you tap in that case.
You should have 2 different views and attach a different gesture recognizer to each one. If ratingControl1 and ratingControl2 are view objects, perhaps you meant to attach the gesture recognizers directly to them, rather than to self.view?
I'm trying to create a keyboard the allows single tap, double tap, and triple tap. So I want to add a UITapGestureRecognizer() to each button in my keyboard. I know how to do this manually from the xib file (add each letter it's own gesture, which would take ages) but not quite sure how to do it in the Controller.
I wrote this for double tap in the viewDidLoad() method:
let doubleTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "doubleTapCharacter:")
doubleTap.numberOfTapsRequired = 2
for button in self.view.subviews{
button.addGestureRecognizer(doubleTap)
}
and created a doubleTapCharacter() method but it's still not working. I also want to be able to send information to the doubleTapCharacter method.
Any help would be much appreciated. Also, I'm very new to swift so if the instructions are complicated, I'd highly appreciate it if you can break it down a little.
create and add the gesture recognizers:
for button in view.subviews {
// create the gesture recognizer
let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: "doubleTapCharacter:")
doubleTapRecognizer.numberOfTapsRequired = 2
// add gesture recognizer to button
button.addGestureRecognizer(doubleTapRecognizer)
}
then implement the target method:
func doubleTapCharacter(doubleTapRecognizer: UITapGestureRecognizer) {
let tappedButton = doubleTapRecognizer.view as! UIButton
print(tappedButton.titleForState(UIControlState.Normal))
}
Here is my issue: I have a transparent UIBUtton hooked up to an action with a control event UIControlEventTouchDownRepeat. Behind this UIButton I have a UIView with the exact same frame as my UIButton, that has a UIGestureRecognizeradded to it.
My question is: Since both views have the same frame, is there a way to dynamically access one or the other depending on the user interaction.
i.e:
If the user double tap on the button, the button will be accessed, other wise, if no UIControlEventTouchDownRepeat is detected, the view behind it will be accessed.
Any ideas on how to proceed ?
Thanks guys
You can add 2 UITapGestureRecognizer to the view without a button and achieve what you are looking for.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let doubleTapGest:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "onTappedTwice")
doubleTapGest.numberOfTapsRequired = 2;
let singleTapGest:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "onTapped")
singleTapGest.numberOfTapsRequired = 1;
singleTapGest.requireGestureRecognizerToFail(doubleTapGest)
self.view.addGestureRecognizer(singleTapGest)
self.view.addGestureRecognizer(doubleTapGest)
}
func onTapped() {
NSLog("Tapped once")
}
func onTappedTwice() {
NSLog("Tapped twice")
}
I am new to swift, please kindly advise the best way to achieve this.
Let say if there are 3 to 4 (custom) UIView(s) added under a parent view
when user select/highlighted a particular one (e.g. the 2nd UIView), and this will get removed and the whole layout will re-render immediately. Any idea?
Connect all views to one IBOutletCollection, add gesture recognizer for tap and in recognizer callback just get the touch point and check if the point is contained in one of the views from the outlet collection.
#IBOutlet var views: [UIView]!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("viewTapped:"))
self.view.addGestureRecognizer(tapGesture)
}
func viewTapped(tapGesture: UITapGestureRecognizer) {
let locationInView = tapGesture.locationInView(view)
for v in views {
if CGRectContainsPoint(v.frame, locationInView) {
v.removeFromSuperview()
}
}
}
Make sure you have your autolayout setup for the state in which each of the view is not there.