I have an image view on scroll view. I added more than one sub views on image view.
->UIScrollView
-->UIImageView
--->UIViews
I want to add gesture recognizer to subviews. But It doesn't work. Where is my mistake? function handleTap() not triggered.
func addSubViewOnImageView(mPoint:CGPoint, mSize: CGSize){
let rect = CGRect(origin: mPoint, size: mSize)
let sView = UIView(frame: rect)
sView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
tap.delegate = self
sView.addGestureRecognizer(tap)
imageView.addSubview(sView)
}
#objc func handleTap(_ sender: UITapGestureRecognizer) {
print("tapped any sub view")
}
This property is inherited from the UIView parent class. This class changes the default value of this property to NO.
enable the user interaction for your imageview, by default its false , for more info you get the info from apple document
imageView.isUserInteractionEnabled = true
just check
yourImageView.isUserInteractionEnabled = true
is there or not?
An Alternate if you don't want to do
yourImageView.isUserInteractionEnabled = true
Just make your UIView class a subclass of UIControl from storyboard refer from screenshot.
it will act as an UIButton no need to write the code for adding an tap gesturejust add an action and likenormally we do for UIImageView`
Related
I am trying to add tap gesture for a dynamically created UILabel in a function in swift 4, but it is not firing UITapGestureRecognizer function. it is working when i add tap gesture from viewDidLoad function, but i have to add tap gesture from other function.
here is the code
override func viewDidLoad() {
super.viewDidLoad()
createLabel()
}
func createLabel() {
let label = UILabel()
label.text = "abc"
label.numberOfLines = 0
label.frame.size.width = self.otherlinksStack.bounds.width
label.font = label.font.withSize(17) // my UIFont extension
label.sizeToFit()
label.tag = 1
self.otherlinksStack.addSubview(label)
let labelTapGesture = UITapGestureRecognizer(target:self,action:#selector(self.doSomethingOnTap))
label.isUserInteractionEnabled = true
label.addGestureRecognizer(labelTapGesture)
}
#objc func doSomethingOnTap() {
print("tapped")
}
You're doing a couple things wrong...
// your code
label.frame.size.width = self.otherlinksStack.bounds.width
label.sizeToFit()
If you're adding the label to a stackView, there is no need to set its frame -- let the stack view handle that. If your stackView's alignment is set to .fill it will stretch the label to its width anyway. If it's not set to fill, the label will expand horizontally as needed, based on its text. So, also, no need to call .sizeToFit().
// your code
self.otherlinksStack.addSubview(label)
When add a view to a stack view, use .addArrangedSubview, otherwise it will be added overlaid on top of another view in the stack view.
This should work fine (it does in my quick test):
func createLabel() {
let label = UILabel()
label.text = "abc"
label.numberOfLines = 0
label.font = label.font.withSize(17) // my UIFont extension
label.tag = 1
// give the label a background color so we can see it
label.backgroundColor = .cyan
// enable user interaction on the label
label.isUserInteractionEnabled = true
// add the label as an Arranged Subview to the stack view
self.otherlinksStack.addArrangedSubview(label)
// create the gesture recognizer
let labelTapGesture = UITapGestureRecognizer(target:self,action:#selector(self.doSomethingOnTap))
// add it to the label
label.addGestureRecognizer(labelTapGesture)
}
#objc func doSomethingOnTap() {
print("tapped")
}
Use this code for adding the Tap Gesture:
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGestureMethod(_:)))
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1
yourLabel.isUserInteractionEnabled = true
yourLabel.addGestureRecognizer(tapGesture)
This is the tap gesture method:
#objc func tapGestureMethod(_ gesture: UITapGestureRecognizer) {
Do your code here
}
func addTapGesture() {
let labelTapGesture = UITapGestureRecognizer(target: self, action: #selector(doSomethingOnTap))
//Add this line to enable user interaction on your label
myLabel.isUserInteractionEnabled = true
myLabel.addGestureRecognizer(labelTapGesture)
}
#objc func doSomethingOnTap() {
print("tapped")
}
Then call addTapGesture() from viewDidLoad or from whichever function you wanna add tap from.
If your gesture works from viewDidLoad, then after adding from other function the gesture might override by other control's gestures..
Try adding gesture on control which is seperate from all other controls.
So what I have is I have a UITapGestureRecognizer for a Tap on the view (lets call that base view) and a UILongPressGestureRecognizer on that same base view. When the user taps the view action one is dispatched and if the user holds down on the view another view pops up. This behavior works nicely.
What I want to do is that the user does not have to separately tap the popup. Instead I want the user to just "pull up" on the popup and activate an action.
I tried to use a UIPanGesture on the popup but that did not work.
Edit
I dragged the long press gesture recognizer on to the view (actually a key in a custom keyboard). This is the code
#IBAction func popupPressed(_ sender: UITapGestureRecognizer) {
//Todo code for popupKey
}
#IBAction func keyPressedLong(_ sender: UILongPressGestureRecognizer) {
switch sender.state {
case .began:
popupTint = UIView(frame: self.frame)
popupTint!.backgroundColor = UIColor.black
popupTint!.alpha = 0.6
self.view.addSubview(popupTint!)
popup = UIView(frame: sender.view!.frame)
popup.frame = CGRect(x: popup.frame.origin.x, y: sender.view!.frame.origin.y - popup.frame.height, width: popup.frame.width, height: popup.frame.height)
popupKey.layer.cornerRadius = 5
popupKey.clipsToBounds = true
let popUpTap = UITapGestureRecognizer(target: self, action: #selector(self.popupPressed(tapGesture:)))
popupKey.addGestureRecognizer(popUpTap)
self.view.addSubview(popup)
default:
break
}
}
Any Ideas ?
Thanks a lot in advance.
UILongPressGestureRecognizer is continuous so you could use the location in the base view to move the popup & check if the movement threshold was met.
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(self.didLongPress(gesture:)))
self.baseView.addGestureRecognizer(longPress)
#objc func didLongPress(gesture: UILongPressGestureRecognizer) {
if self.popUpView.bounds.contains(gesture.location(in: self.popUpView)) {
// perform action
}
}
I hope this answers your question.
I added a label and an image to the navigation item title view, like this - https://stackoverflow.com/a/38548905/1373592
And I added these three lines of code, to make the title clickable.
....
let recognizer = UITapGestureRecognizer(target: self, action: #selector(MyViewController.titleTapped(_:)))
navView.isUserInteractionEnabled = true
navView.addGestureRecognizer(recognizer)
And this titleTapped function.
#objc func titleTapped(_ tapGestureRecognizer: UITapGestureRecognizer) {
print("Tapped")
}
What am I doing wrong?
I tried adding gesture recognizer to the label, and to the image (separately). That didn't work either.
Thanks.
Your NavView has no frame, so there is nothing "there" to tap.
Add this line:
// Create a navView to add to the navigation bar
let navView = UIView()
// new line
navView.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
// Create the label
let label = UILabel()
and you should be on your way.
100% sure working in my app and well tested.
var tapGesture = UITapGestureRecognizer()
take your view and set IBOutlet like:
#IBOutlet weak var viewTap: UIView!
Write pretty code on viewDidLoad() like:
tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.myviewTapped(_:)))
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1
viewTap.addGestureRecognizer(tapGesture)
viewTap.isUserInteractionEnabled = true
this method is calling when tap gesture recognized
#objc func myviewTapped(_ sender: UITapGestureRecognizer) {
if self.viewTap.backgroundColor == UIColor.yellow {
self.viewTap.backgroundColor = UIColor.green
}else{
self.viewTap.backgroundColor = UIColor.yellow
}
}
Note: In your case you have to sure for view which view infront like UILabel or UIView that is nav and then assign the gesture to it.If your label cover the whole view then let's try to give gesture to label only.
I want to remove UIView from screen after user tap something except that view. (to visualize it for you I will upload sketch of my view)
And I want to remove blue UIView after user tap on something except buttons in this view. What should I use?
EDIT:
In blue UIView are two buttons and I want to remove that view when user tap on background image
I did what #yerpy told me to do but it isn't working.
func test(gestureRecognizer: UITapGestureRecognizer) {
print("test")
}
func setUpBackgroundImageView() {
self.view.addSubview(backgroundImageView)
backgroundImageView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
backgroundImageView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
backgroundImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
backgroundImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
let tap = UITapGestureRecognizer(target: self, action: #selector(test(gestureRecognizer:)))
backgroundImageView.addGestureRecognizer(tap)
tap.delegate = self
}
And I also add shouldReceiveTouch function to UIGestureRecognizerDelegate. What am I doing wrong?
Add UIGestureRecognizer to the super view :
As you said you have image view as a background.
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped(gestureRecognizer:)))
imageView.addGestureRecognizer(tapRecognizer)
tapRecognizer.delegate = self
Adding target action :
func tapped(gestureRecognizer: UITapGestureRecognizer) {
// Remove the blue view.
}
And then inside UITapGestureRecognizerDelegate :
extension ViewController : UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view!.superview!.superclass! .isSubclass(of: UIButton.self) {
return false
}
return true
}
}
Hope it helps !
EDIT
Make sure that user can touch on the view by enabling : self.view.userInteractionEnabled = true
1- Add a view below your view, let call it overlay (gray one)
2- Add your container view with all your buttons inside (green one)
3- Add a tap gesture to the overlay (drag tap to overlay view)
4- Create a #IBAction of the tap to the viewcontroller
5- Write code to hide your green view inside the #IBAction
Image
Image
you can use UITapGestureRecognizer for that view
override func viewDidLoad() {
super.viewDidLoad()
// Add "tap" press gesture recognizer
let tap = UITapGestureRecognizer(target: self, action: #selector(tapHandler))
tap.numberOfTapsRequired = 1
backgroundimage.addGestureRecognizer(tap)
}
// called by gesture recognizer
func tapHandler(gesture: UITapGestureRecognizer) {
// handle touch down and touch up events separately
if gesture.state == .began {
} else if gesture.state == .ended {
}
}
You can
subclass with that background view, and implement an inherited method -beganTouches:(there is another para but I forget what it is)
Add a UITapGestureRecognizer to that view
Add a giant button that covers the entire screen under all the buttons. Anytime the user presses on the giant button underneath the smaller buttons, do what you want it to do.
Not the most elegant but it works :P
I've the following code to add a gesture recognizer to a UILabel. User Interaction Enabled is ticked on for the label in the storyboard, but when I tap on the label the onUserClickingSendToken method is not being called.
class ViewController: UIViewController, MFMailComposeViewControllerDelegate {
#IBOutlet weak var tokenDisplay: UILabel!
var tapGestureRecognizer:UITapGestureRecognizer = UITapGestureRecognizer(target:self, action: #selector(onUserClickingSendToken(_:)))
override func viewDidLoad() {
super.viewDidLoad()
tapGestureRecognizer.numberOfTapsRequired = 1
tokenDisplay.addGestureRecognizer(tapGestureRecognizer)
}
func onUserClickingSendToken(_ sender: Any)
{
....
Initializing the tapRecognizer in viewDidLoad should do it, cause you were targeting self before the view was initialized
class ViewController: UIViewController, MFMailComposeViewControllerDelegate {
#IBOutlet weak var tokenDisplay: UILabel!
var tapGestureRecognizer:UITapGestureRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
tapGestureRecognizer = UITapGestureRecognizer(target:self, action: #selector(onUserClickingSendToken(_:)))
tapGestureRecognizer.numberOfTapsRequired = 1
tokenDisplay.isUserInteractionEnabled = true
tokenDisplay.addGestureRecognizer(tapGestureRecognizer)
}
#objc func onUserClickingSendToken(_ sender: Any)
{
....
In general for UILabel clickable issue:
There are couple of reasons why your UILabel will not work as clickable
Make sure to mark UILabel UserInteraction true and if yourLabel is inside other view than mark that view UserInteraction true too.
yourLabel.isUserInteractionEnabled = true
Assigning self to target before the view initialisation, move your code inside viewDidLoad/awakeFromNib or after view Load
let tap = UITapGestureRecognizer(target: self, action: #selector(onClickLabel(_:)))
self.yourLabel.addGestureRecognizer(tap)
If you are adding UILabel programmatically, than you have to assign it's frame too.
yourLabel.frame = CGRect(x: 0, y: 0, width: 300, height: 20)
Super view in which your UILabel is should be large enough to fit/display label properly, if your label is inside some view than that view's height/weight should assign in a way that it cover the whole UILabel frame.
In my case this was the problem I had, I tried so many thing but at last it turns out that the view in which I had my label had fixed width, the label was displaying properly but onClick event was't working due to out of frame.
It was missing UILabel's trailing constraints, so half of the thing is not clickable.
Using same tab gesture for multiple view, you cannot use one tab gesture for more than one view or labels,use different for each UILabel.
try this:
let tap = UITapGestureRecognizer(target: self, action: #selector(onClickLabel(_:)))
self.yourLabel.isUserInteractionEnabled = true
self.yourLabel.addGestureRecognizer(tap)
let tap2 = UITapGestureRecognizer(target: self, action: #selector(onClickLabel(_:)))
self.someView.isUserInteractionEnabled = true
self.someView.addGestureRecognizer(tap2)
instead of this:
let tap = UITapGestureRecognizer(target: self, action: #selector(onClickLabel(_:)))
self.yourLabel.isUserInteractionEnabled = true
self.yourLabel.addGestureRecognizer(tap)
self.someView.isUserInteractionEnabled = true
self.someView.addGestureRecognizer(tap)
// tapGesture will work on only one element
Try changing your selector setup to:
#selector(ViewController .onUserClickingSendToken(_:).