How to assign an action for UIImageView object in Swift
Asked Answered
S

12

230

I'm trying to assign an UIImageView to an action when the user taps it.

I know how to create an action for a UIButton, but how could I mimic the same behavior of a UIButton, but using a UIImageView?

Stableboy answered 10/1, 2015 at 19:59 Comment(0)
F
531

You'll need a UITapGestureRecognizer. To set up use this:

override func viewDidLoad()
{
    super.viewDidLoad()

    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
    imageView.isUserInteractionEnabled = true
    imageView.addGestureRecognizer(tapGestureRecognizer)
}

@objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
    let tappedImage = tapGestureRecognizer.view as! UIImageView

    // Your action
}

(You could also use a UIButton and assign an image to it, without text and than simply connect an IBAction)

Fortunia answered 10/1, 2015 at 20:5 Comment(9)
as stated below by MidHun MP, make sure you have the userInteractionEnabled = trueCymbre
is it possible to add action for UIImageView without using UITapGestureRecognizer?Thornton
You could create a subclass of UIImageView and handle touches via touchesBegan: and touchesEnded:, but using a gestureRecognizer is definitely the most convenient way.Fortunia
@Stableboy you used the button as an image.but i want aspect fit for my images. then what?Dodson
Using Swift 4, this worked for me, but I had to add an @objc modifier to the function.Cottrell
Nice and concise solution! Although I prefer the button also because it can handle selection states better and have a better user experience in general, while images simply don't have that by default.Ramachandra
How can I pass argument inside "imageTapped" function?Teeterboard
You can only pass another parameter for the event: func foo(sender: Any, forEvent event: UIEvent). To pass other values you can create a custom UITapGestureRecognizer: class CustomTapGestureRecognizer: UITapGestureRecognizer and add a field that represents your data. E.g. let tapGesture = CustomTapGestureRecognizer(target: self, action: #selector(tapSelector(sender:))) tapGesture.ourCustomValue = "someStringValue" You can read more about it hereCepheus
NOTE: The view must already be in the view hierarchy, before you add gesture recognizers. Otherwise they won't work.Rivet
P
81

You need to add a a gesture recognizer (For tap use UITapGestureRecognizer, for tap and hold use UILongPressGestureRecognizer) to your UIImageView.

let tap = UITapGestureRecognizer(target: self, action: #selector(YourClass.tappedMe))
imageView.addGestureRecognizer(tap)
imageView.isUserInteractionEnabled = true

And Implement the selector method like:

@objc func tappedMe()
{
    println("Tapped on Image")
}
Paquette answered 10/1, 2015 at 20:5 Comment(5)
userInteractionEnabled is key.Peltz
@hatim: What is the issue you are facing ? If you have a new issue, please post it as a new question.Paquette
@MidhunMP I am generating the image view dynamically and have done exactly what is written in this answer but tappedMe() function is not getting calledJumble
It worked for me with the following changes: let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.tappedMe)) // next line -> successIndicatorImg.addGestureRecognizer(tap) // next line -> successIndicatorImg.isUserInteractionEnabled = trueAlpers
@Jumble are you using same gesture to multiple UI views ? I just solved this issue as i was using same gesture for multiple views and only one was working for me. when i create multiple gestures it worked for me.Heartsome
K
37

You can add a UITapGestureRecognizer to the imageView, just drag one into your Storyboard/xib, Ctrl-drag from the imageView to the gestureRecognizer, and Ctrl-drag from the gestureRecognizer to the Swift-file to make an IBAction.

You'll also need to enable user interactions on the UIImageView, as shown in this image: enter image description here

Karlsbad answered 10/1, 2015 at 20:7 Comment(3)
UIImageView doesn't respond to touches by default. You also have to enable user interactions.Nonobjective
@Nonobjective Oops, that's true. Edited.Karlsbad
I like how you can set this up using the IB, drag/drop is powerful, and didn't expect it was possible. +1 for that. As a noob, it would be easy to not know how it's connected without "mousing around" the storyboard. It depends on your preference, but I prefer to "see it in code".Moorehead
S
21

For Swift do this:

@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.tappedMe))
    imageView.addGestureRecognizer(tap)
    imageView.isUserInteractionEnabled = true
}

func tappedMe() {
    print("Tapped on Image")
}
Starstarboard answered 4/9, 2016 at 6:27 Comment(0)
M
16

Swift4 Code

Try this some new extension methods:

import UIKit

extension UIView {

    fileprivate struct AssociatedObjectKeys {
        static var tapGestureRecognizer = "MediaViewerAssociatedObjectKey_mediaViewer"
    }

    fileprivate typealias Action = (() -> Void)?


    fileprivate var tapGestureRecognizerAction: Action? {
        set {
            if let newValue = newValue {
                // Computed properties get stored as associated objects
                objc_setAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
            }
        }
        get {
            let tapGestureRecognizerActionInstance = objc_getAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer) as? Action
            return tapGestureRecognizerActionInstance
        }
    }


    public func addTapGestureRecognizer(action: (() -> Void)?) {
        self.isUserInteractionEnabled = true
        self.tapGestureRecognizerAction = action
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
        self.addGestureRecognizer(tapGestureRecognizer)
    }


    @objc fileprivate func handleTapGesture(sender: UITapGestureRecognizer) {
        if let action = self.tapGestureRecognizerAction {
            action?()
        } else {
            print("no action")
        }
    }

}

Now whenever we want to add a UITapGestureRecognizer to a UIView or UIView subclass like UIImageView, we can do so without creating associated functions for selectors!

Usage:

 profile_ImageView.addTapGestureRecognizer {
        print("image tapped")
    }
Massie answered 17/12, 2018 at 5:9 Comment(5)
Works great. and it very much simplified the implementation by far.Calefaction
scares me a bit with the reflection functions used - is there a good chance of this going to work in future swift versions?Batsman
This is very elegant and helpful. Works for meParmenter
❤️I love extensionsOrthopter
outstanding workMier
B
11

You could actually just set the image of the UIButton to what you would normally put in a UIImageView. For example, where you would do:

myImageView.image = myUIImage

You could instead use:

myButton.setImage(myUIImage, forState: UIControlState.Normal)

So, here's what your code could look like:

override func viewDidLoad(){
  super.viewDidLoad()

  var myUIImage: UIImage //set the UIImage here
  myButton.setImage(myUIImage, forState: UIControlState.Normal)
}

@IBOutlet var myButton: UIButton!
@IBAction func buttonTap(sender: UIButton!){
  //handle the image tap
}

The great thing about using this method is that if you have to load the image from a database, you could set the title of the button before you set the image:

myButton.setTitle("Loading Image...", forState: UIControlState.Normal)

To tell your users that you are loading the image

Bevy answered 10/1, 2015 at 20:5 Comment(0)
R
7

Need to add lazy for TapGestureRecognizer to register
since the 'self' in UITapGestureRecognizer(target: self ...) will be nil if it's not a lazy var. Even if you set isUserInteractionEnable = true, it won't register without lazy var.

lazy var imageSelector : UIImageView = {
    let image = UIImageView(image: "imageName.png")
    //now add tap gesture
    image.isUserInteractionEnabled = true
    image.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleImageSelector)))
    return image
}()
@objc private func handleImageSelector() {
    print("Pressed image selector")
}
Randyranee answered 26/11, 2019 at 9:5 Comment(1)
Is this possible to declare the function inside action: argument ? Something like this : image.addGestureRecognizer(UITapGestureRecognizer(target: self, action: { print ("ok") }))Jipijapa
B
2

You can put a UIButton with a transparent background over top of the UIImageView, and listen for a tap on the button before loading the image

Bialy answered 11/7, 2015 at 2:26 Comment(2)
Its a swift way of describing an option. I thought everyone knew that!Bialy
It is not a good idea to add unnecessary UI components without any real reason. It will increase the complexity of the UI and also you have to deal with the same auto layout constraints. It is just better to add a TapGestureRecognizer.Rockaway
T
2
@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
//ViewController is your current view controller    
let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.tappedMe))
    imageView.addGestureRecognizer(tap)
    imageView.isUserInteractionEnabled = true
}

// Need to ass objective-c annotation 
@objc
func tappedMe() {
    print("Tapped on Image")
}
Texture answered 10/2, 2022 at 16:10 Comment(2)
Your answer seems very similar to Kumar's at first glance, but there are some differences. And can you talk about the different places : )Corybantic
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Nicknack
F
1

Swift 4 Code


Step 1 In ViewdidLoad()

   let pictureTap = UITapGestureRecognizer(target: self, action: #selector(MyInfoTableViewController.imageTapped))
       userImageView.addGestureRecognizer(pictureTap)
       userImageView.isUserInteractionEnabled = true

Step 2 Add Following Function

@objc func imageTapped() {

        let imageView = userImageView
        let newImageView = UIImageView(image: imageView?.image)
        newImageView.frame = UIScreen.main.bounds
        newImageView.backgroundColor = UIColor.black
        newImageView.contentMode = .scaleAspectFit
        newImageView.isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer(target: self, action: #selector(dismissFullscreenImage))
        newImageView.addGestureRecognizer(tap)
        self.view.addSubview(newImageView)

        self.navigationController?.isNavigationBarHidden = true
        self.tabBarController?.tabBar.isHidden = true

    }

It's Tested And Working Properly

Fibula answered 1/8, 2018 at 10:38 Comment(0)
P
0

I suggest to place invisible(opacity = 0) button on your imageview and then handle interaction on button.

Pseudo answered 22/5, 2019 at 10:33 Comment(0)
W
0

This is what I found, much easier to setup.

Here is the YouTube video

  1. Open the Library, look for "Tap Gesture Recognizer" object.
  2. Drag the object to your storyboard, and set the delegate to the image you want to trigger actions.
  3. Then go to the view controller, drag the same object to set the IBAction.
Westfahl answered 11/4, 2021 at 2:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.