171

I would like to make a UILabel clickable.

I have tried this, but it doesn't work:

class DetailViewController: UIViewController {

    @IBOutlet weak var tripDetails: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        let tap = UITapGestureRecognizer(target: self, action: Selector("tapFunction:"))
        tripDetails.addGestureRecognizer(tap)
    }

    func tapFunction(sender:UITapGestureRecognizer) {
        print("tap working")
    }
}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Daniele B
  • 19,801
  • 29
  • 115
  • 173
  • 4
    What is the frame of your `UILabel`? Are you sure you're touching in the label's frame? Do you have an `UIViews` covering the label? Is `userInteractionEnabled` set to `True` for the label? – JAL Nov 11 '15 at 19:48
  • Make sure your UILabel IBOutlet is hooked up from your Nib or Storyboard – aahrens Nov 11 '15 at 19:50

12 Answers12

208

Have you tried to set isUserInteractionEnabled to true on the tripDetails label? This should work.

Mohamed ALOUANE
  • 5,349
  • 6
  • 29
  • 60
Claudiu Iordache
  • 2,215
  • 1
  • 10
  • 5
  • 1
    thanks for the answer!!! Here I have another issue still about UITapGestureRecognizer: http://stackoverflow.com/questions/33659078/swift-how-to-make-a-uiview-clickable-in-uitableviewcell – Daniele B Nov 11 '15 at 20:22
  • I am trying to change background color on tap but the tap event is firing when i release my finger. Is there a way to catch touch down event? Long press is not what i am looking for. – Numan Karaaslan Aug 23 '17 at 12:21
  • oh, wow so label by default is not user interact-able, appreciate it! – Dan Feb 17 '21 at 08:41
131

Swift 3 Update

Replace

Selector("tapFunction:")

with

#selector(DetailViewController.tapFunction)

Example:

class DetailViewController: UIViewController {

    @IBOutlet weak var tripDetails: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        ...

        let tap = UITapGestureRecognizer(target: self, action: #selector(DetailViewController.tapFunction))
        tripDetails.isUserInteractionEnabled = true
        tripDetails.addGestureRecognizer(tap)
    }

    @objc
    func tapFunction(sender:UITapGestureRecognizer) {
        print("tap working")
    }
}
Pablo Sanchez Gomez
  • 1,438
  • 16
  • 28
liorco
  • 1,483
  • 1
  • 9
  • 12
53

SWIFT 4 Update

 @IBOutlet weak var tripDetails: UILabel!

 override func viewDidLoad() {
    super.viewDidLoad()

    let tap = UITapGestureRecognizer(target: self, action: #selector(GameViewController.tapFunction))
    tripDetails.isUserInteractionEnabled = true
    tripDetails.addGestureRecognizer(tap)
}

@objc func tapFunction(sender:UITapGestureRecognizer) {

    print("tap working")
}
Xcodian Solangi
  • 2,342
  • 5
  • 24
  • 52
30

Swift 5

Similar to @liorco, but need to replace @objc with @IBAction.

class DetailViewController: UIViewController {

    @IBOutlet weak var tripDetails: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        ...

        let tap = UITapGestureRecognizer(target: self, action: #selector(DetailViewController.tapFunction))
        tripDetails.isUserInteractionEnabled = true
        tripDetails.addGestureRecognizer(tap)
    }

    @IBAction func tapFunction(sender: UITapGestureRecognizer) {
        print("tap working")
    }
}

This is working on Xcode 10.2.

Jerry Chong
  • 7,954
  • 4
  • 45
  • 40
  • 4
    `@IBAction` is only needed to expose method to Xcode's Interface Builder (hence IB). It also acts as `@objc` but if you add the gestures or other actions with code you should use the `@objc` annotation – Adam Aug 16 '19 at 08:25
16

Swift 3 Update

yourLabel.isUserInteractionEnabled = true
Indrajit Sinh Rayjada
  • 1,243
  • 1
  • 14
  • 24
16

Good and convenient solution:

In your ViewController:

@IBOutlet weak var label: LabelButton!

override func viewDidLoad() {
    super.viewDidLoad()

    self.label.onClick = {
        // TODO
    }
}

You can place this in your ViewController or in another .swift file(e.g. CustomView.swift):

@IBDesignable class LabelButton: UILabel {
    var onClick: () -> Void = {}
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        onClick()
    }
}

In Storyboard select Label and on right pane in "Identity Inspector" in field class select LabelButton.

Don't forget to enable in Label Attribute Inspector "User Interaction Enabled"

researcher
  • 1,758
  • 22
  • 25
  • 1
    Inside viewDidLoad() need to add this line if doesn't work: self.label.isUserInteractionEnabled = true – Touhid Nov 19 '20 at 15:27
4

You need to enable the user interaction of that label.....

For e.g

yourLabel.userInteractionEnabled = true

Nandkishor mewara
  • 2,552
  • 16
  • 29
Abhishek
  • 509
  • 3
  • 12
3

For swift 3.0 You can also change gesture long press time duration

label.isUserInteractionEnabled = true
let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer.init(target: self, action: #selector(userDragged(gesture:))) 
longPress.minimumPressDuration = 0.2
label.addGestureRecognizer(longPress)
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
DURGESH
  • 2,373
  • 1
  • 15
  • 13
3

Thanks researcher

Here's my solution for programmatic user interface using UIKit.

I've tried it only on Swift 5. And It worked.

Fun fact is you don't have to set isUserInteractionEnabled = true explicitly.

import UIKit

open class LabelButon: UILabel {
    var onClick: () -> Void = {}
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        isUserInteractionEnabled = true
    }
    
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    public convenience init() {
        self.init(frame: .zero)
    }
    
    open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        onClick()
    }
}

Uses:

override func viewDidLoad() {
    super.viewDidLoad()
    
    let label = LabelButton()
    label.text = "Label"
    label.onClick = {
        // TODO
    }
}

Don't forget to set constraints. Otherwise it won't appear on view.

Md. Arif
  • 448
  • 1
  • 5
  • 13
2

Pretty easy to overlook like I did, but don't forget to use UITapGestureRecognizer rather than UIGestureRecognizer.

Devbot10
  • 1,193
  • 18
  • 33
0

On top of all of the other answers, this depends on where the label is, it might be behind some subviews. You might think you tap on the label but maybe click the top view. To solve this you can bring the label view to the front with the following line.

self.view.bringSubviewToFront(lblView)
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
kutay
  • 11
  • 4
-4

As described in the above solution you should enable the user interaction first and add the tap gesture

this code has been tested using

Swift4 - Xcode 9.2

yourlabel.isUserInteractionEnabled = true
yourlabel.addGestureRecognizer(UITapGestureRecognizer(){
                //TODO 
            })
Community
  • 1
  • 1
Amr Angry
  • 3,711
  • 1
  • 45
  • 37
  • I get `Cannot invoke initializer for type 'UITapGestureRecognizer' with an argument list of type '(() -> Void)'` when I try this. – lionello Sep 20 '18 at 11:53