b.gibson
b.gibson

Reputation: 121

Adding a gesture recognizer to an image view in a table cell

How can I add a Gesture Recognizer to a UIImageView in a table cell? I want it so that if a user taps an image in the cell, the image will change and the data model will update.

I know this needs to be set up in the UITableViewController. My code currently can execute a command if anywhere in the cell is tapped, but I would like it to execute only if the image is tapped, not anywhere in the cell.

I setup up the gesture recognizer in viewDidLoad

override func viewDidLoad() {
    super.viewDidLoad()

    // Load sample data
    loadSampleHabits()

    // Initialize tap gesture recognizer
    var recognizer = UITapGestureRecognizer(target: self, action: #selector(tapEdit(recognizer:)))
    // Add gesture recognizer to the view
    self.tableView.addGestureRecognizer(recognizer)

And this is the function

//action method for gesture recognizer
func tapEdit(recognizer: UITapGestureRecognizer) {
    if recognizer.state == UIGestureRecognizerState.ended {
        let tapLocation = recognizer.location(in: self.tableView)
        if let tapIndexPath = self.tableView.indexPathForRow(at: tapLocation) {
            if let tappedCell = self.tableView.cellForRow(at: tapIndexPath) as? HabitTableViewCell {
                print("Row Selected")

            }
        }
    }

What the cell looks like

As a secondary question, are there any conflicts if I want to add a gesture recognizer to the cell and the image view within the cell?

Upvotes: 12

Views: 9794

Answers (6)

shikarikutta
shikarikutta

Reputation: 11

import UIKit

class UserInfoCell: UITableViewCell{

    @IBOutlet weak var imagePlaceholder: UIImageView!
}

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UIImagePickerControllerDelegate,UINavigationControllerDelegate {

    @IBOutlet weak var tableView: UITableView!


    let imagePicker = UIImagePickerController()
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 1


    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cell = tableView.dequeueReusableCell(withIdentifier: "UserInfoCell" ,for: indexPath ) as! UserInfoCell
            let recognizer = UITapGestureRecognizer(target: self, action: #selector(self.openGallery))

            cell.imagePlaceholder.addGestureRecognizer(recognizer)
            recognizer.numberOfTapsRequired = 1
            cell.imagePlaceholder.isUserInteractionEnabled = true
            cell.name.text = "Akshay"

            if let data = UserDefaults.standard.data(forKey: "savedImage") {
                cell.imagePlaceholder.image = UIImage(data: data as Data)
            }

            return cell




    }
    @objc func openGallery(){
        imagePicker.sourceType = .photoLibrary
        present(imagePicker,animated:  true, completion: nil)
    }
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        let userimage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
        let imageData = userimage.jpegData(compressionQuality: 1)!
        UserDefaults.standard.setValue(imageData, forKey: "savedImage")
        print("image found")
        self.imagePicker.dismiss(animated: true, completion: nil)

        self.tableView.reloadData()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        imagePicker.delegate = self
tableView.tableFooterView = UIView()

    }
}

This code select image from gallery using Tapgesture of ImageView inside a TableViewCell

Upvotes: 1

selva raj
selva raj

Reputation: 164

// create an instance of UITapGestureRecognizer and tell it to run 
// an action we'll call "handleTap:"
let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
// we use our delegate
tap.delegate = self
// allow for user interaction
cell.imageViewName.userInteractionEnabled = true
// add tap as a gestureRecognizer to tapView
cell.imageViewName.addGestureRecognizer(tap)

Upvotes: 3

luckyShubhra
luckyShubhra

Reputation: 2751

You are adding gesture recognizer on your tableview instead of imageView as you required. Yo need to move your code from viewDidLoad to cellForRowAtIndexPath and add gesture to imageView in each cell while configuing your cell.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
     var recognizer = UITapGestureRecognizer(target: self, action: #selector(tapEdit(recognizer:)))
     // Add gesture recognizer to your image view
     cell.yourimageview.addGestureRecognizer(recognizer)
}

Note: Do make sure to enable userinteraction of your image view

cell.yourimageview.userInteractionEnabled = YES;

For your requirement I will suggest using UILongPressGestureRecognizer as it has less chances of conflict in gesture and didselect. Yo can add UILongPressGestureRecognizer in viewDidLoad and access it as per your requirement.

let lpgr = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.handleLongPress(_:)))
lpgr.minimumPressDuration = 1
tableView.addGestureRecognizer(lpgr)

Define method as

func handleLongPress(_ gesture: UILongPressGestureRecognizer){
if gesture.state != .began { return }
let tapLocation = gesture.location(in: self.tableView)
    if let tapIndexPath = self.tableView.indexPathForRow(at: tapLocation) {
        if let tappedCell = self.tableView.cellForRow(at: tapIndexPath) as? HabitTableViewCell {
            print("Row Selected")

        }
}

You can try removing if recognizer.state == UIGestureRecognizerState.ended condition from your method.

UITapGestureRecognizer is a discrete gesture, and as such, your event handler is called only once when the gesture was recognized. You don't have to check the state at all. Certainly you won't receive a call for the state of .Began. For more info consider @Rob ans here.

Upvotes: 17

BHAVIK
BHAVIK

Reputation: 899

Add This line in cell for row at index path

     var recognizer = UITapGestureRecognizer(target: self, action: #selector(tapEdit(recognizer:)))
        // Add gesture recognizer to the view
        cell.yourimageviewname.addGestureRecognizer(recognizer)

cell.yourimageviewname.userInteractionEnabled = true;

Upvotes: 4

Codus
Codus

Reputation: 1473

I have had design a solution like this. I just write a sample code below:

import UIKit

protocol CellImageTapDelegate {
    func tableCell(didClickedImageOf tableCell: UITableViewCell)
}

class SampleCell : UITableViewCell {

    var delegate : CellImageTapDelegate?
    var tapGestureRecognizer = UITapGestureRecognizer()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initialize()
    }

    private func initialize() {
        tapGestureRecognizer.addTarget(self, action: #selector(SampleCell.imageTapped(gestureRecgonizer:)))
        self.addGestureRecognizer(tapGestureRecognizer)
    }

    func imageTapped(gestureRecgonizer: UITapGestureRecognizer) {
        delegate?.tableCell(didClickedImageOf: self)
    }
}

class ViewController: UITableViewController, CellImageTapDelegate {

    // CellImageTapDelegate
    func tableCell(didClickedImageOf tableCell: UITableViewCell) {
        if let rowIndexPath = tableView.indexPath(for: tableCell) {
            print("Row Selected of indexPath: \(rowIndexPath)")
        }
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "SampleCellID", for: indexPath) as! SampleCell
        cell.delegate = self
        return cell
    }
}

remember to do following in storyboard 1. enable user interaction of imageview 1. enable user interaction of imageview 2. set class of tableviewcell 2. set class of tableviewcell 3. set reuse identifier of tableviewcell
3. set reuse identifier of tableviewcell

Upvotes: 4

Bhavesh Dhaduk
Bhavesh Dhaduk

Reputation: 1906

For my suggestion you have to use UIButton in cell, for performance improvements,

UIButtons

Specially designed for this and have been extensively optimized by Apple for touches.

If you want image in cell you can use UIButton with Image inside.

Upvotes: 3

Related Questions