Reputation: 121
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")
}
}
}
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
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
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
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
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
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
2. set class of tableviewcell
3. set reuse identifier of tableviewcell
Upvotes: 4
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