Gesturerecogniser for image in tableviewcell in swift3 - ios

I'm facing a problem in using UITapGestureRecogniser for an image in tableViewCell. I've created an outlet of object UIImageView in tableViewCell and my requirement is whenever I click on that imageView other image has to be displayed. I've tried the code below, but it didn't work.
Any help would be appreciated!!
Cell
import UIKit
class resultsTableViewCell: UITableViewCell {
#IBOutlet weak var star_selected: UIImageView!
#IBOutlet weak var star_unselected: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
View controller
class resultsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate {
#IBOutlet weak var resultsTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
flightCodeView = FlightCodeView(frame: CGRect.zero)
self.view.addSubview(flightCodeView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultsCellIdentifier", for: indexPath) as! resultsTableViewCell
let image : UIImage = UIImage(named: "star_unselected")!
cell.star_unselected.image = image
let tapGesture = UITapGestureRecognizer(target: self, action: Selector(("ImageSelected")))
cell.star_unselected.addGestureRecognizer(tapGesture)
tapGesture.delegate = self
return cell
}
func ImageSelected(sender: UITapGestureRecognizer? = nil) {
// just creating an alert to prove our tap worked!
let image: UIImage = UIImage(named: "star_selected.png")!
cell.star_selected.image = image
}
}

Check this:
imageView.isUserInteractionEnabled = true

add this code just below tapgesure variable ...
cell.userInteractionEnabled = true
cell.addGestureRecognizer(tapGesture)
I hope this will help..

Add this code in cellForRowAt:
cell.star_unselected.userInteractionEnabled = true
The function will look like :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultsCellIdentifier", for: indexPath) as! resultsTableViewCell
let image : UIImage = UIImage(named: "star_unselected")!
cell.star_unselected.image = image
cell.star_unselected.userInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: Selector(("ImageSelected")))
cell.star_unselected.addGestureRecognizer(tapGesture)
tapGesture.delegate = self
return cell
}

Related

Delegate always nil in tableviewcontroller

I am trying to pass data from my tableViewController to my ProfileViewController. so when i clicked cell, then my profile textfield will set the text to the cell that i clicked before.
This is my TableViewController .
protocol TableViewDelegate {
func clickedTableViewCell(info: String)
}
class ProfilePlaceTableViewController : UITableViewController {
var delegate: TableViewDelegate!
#IBOutlet var tableViewProfile: UITableView!
let foods = ["tomato", "red", "rice", "milk", "cheese"]
override func viewDidLoad() {
super.viewDidLoad()
tableViewProfile.delegate = self
tableViewProfile.dataSource = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return foods.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = foods[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (tableView.cellForRow(at:indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark) {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
} else {
tableView.cellForRow(at:indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
}
//getting the index path of selected row
let indexPath = tableView.indexPathForSelectedRow
//getting the current cell from the index path
let currentCell = tableView.cellForRow(at: indexPath!)! as UITableViewCell
//getting the text of that cell
let currentItem = currentCell.textLabel!.text
print("currentItem : ", currentItem!)
if (delegate != nil) {
self.delegate?.clickedTableViewCell(info: currentItem!)
self.dismiss(animated: true, completion: nil)
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
}
This is my profileViewController .
class ProfileViewController : UIViewController, TableViewDelegate {
#IBOutlet weak var provinceText: kTextFiledPlaceHolder!
var profilePlaceTableViewController = ProfilePlaceTableViewController()
func clickedTableViewCell(info: String) {
provinceText.text = info
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showProfilePlace" {
let showProfileVc: ProfilePlaceTableViewController = segue.destination as! ProfilePlaceTableViewController
showProfileVc.delegate = self
}
}
override func viewDidLoad() {
let button = UIButton.init(type: .custom)
button.setImage(UIImage.init(named: "ic_hamburger_menu"), for: UIControlState.normal)
button.setTitleColor(UIColor.black, for: .normal)
button.addTarget(self.revealViewController(), action:#selector(SWRevealViewController.revealToggle(_:)), for: UIControlEvents.touchUpInside)
button.sizeToFit()
button.imageEdgeInsets = UIEdgeInsetsMake(4, 4, 4, 4)
let barButton = UIBarButtonItem.init(customView: button)
self.navigationItem.leftBarButtonItem = barButton
self.view.addGestureRecognizer(self.revealViewController().tapGestureRecognizer())
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
provinceText.addTarget(self, action: #selector(provinceClicked(_:)), for: .touchDown)
profilePlaceTableViewController.delegate = self
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func provinceClicked(_ textField: UITextField) {
performSegue(withIdentifier: "showProfilePlace", sender: nil)
}
I have done all this and follow many tutorials but still no solution. Any help would be appreciated. Thank you.
You've declared your delegate (TableViewDelegate) as non-optional, but in the didSelect method, you're using optional chaining - self.delegate?.clickedTableViewCell(info: currentItem!)
Declare your delegate as weak optional property - weak var delegate: TableViewDelegate? = nil to avoid retain cycle.
Delete your profilePlaceTableViewController.delegate = self. You're doing the same in your performSegue method.
And change your protocol declaration to:
protocol TableViewDelegate: class {
func clickedTableViewCell(info: String)
}

Swift PickerView with custom tableViewCell.xib

I am messing around with swift and i am stuck in creating an UIPickerView connection with a custom TableViewCell.xib. The functionality i want is the following: when i press the switch button a pickerView appears that lets me select a month which will appear instead of the "Select Month" label. I don't really understand where should i create the outlets.
Cell Xib
Main StoryBoard
class TableViewCell: UITableViewCell {
#IBOutlet weak var leftImage: UIImageView!
#IBOutlet weak var label: UILabel!
#IBOutlet weak var rightImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func commonInit(_ imageName1: String, _ imageName2: String, text: String){
leftImage.image = UIImage(named: imageName1)
rightImage.image = UIImage(named: imageName2)
label.text = text
}
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let textData = ["Select Month"]
let datePicker = UIDatePicker()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "UiTableView"
tableView.delegate = self
tableView.dataSource = self
let nibName = UINib(nibName: "TableViewCell", bundle: nil)
tableView.register(nibName, forCellReuseIdentifier: "tableViewCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return textData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! TableViewCell
cell.commonInit("facebook", "twitter", text: textData[indexPath.item])
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 170
}
func createDatePicker(){
let toolBar = UIToolbar()
toolBar.sizeToFit()
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: nil)
toolBar.setItems([doneButton], animated: false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Open up the Cell Xib file and choose from the Menu, View>Assistand Editor>Show Assistant Editor. Once the Assistant Editor is open you can open the TableViewCell class. Control Drag from the 3 controls in the XIB in Interface builder to the corresponding entry in the file. Once over the entry such as #IBOutlet weak var leftImage: UIImageView!, it will highlight. Release the mouse and the connection will be established.
It is actually a little bit easier to not type the line with the outlet declaration in the class first. In this case, when you control drag from ID you position the mouse over an empty line and a dialog box appears where you can declare the outlet. It creates the connection at the same time.

UITableView doesn't show anything

I wrote an app that it have a UITableView in UIViewController and here is my codes:
class CategorySelectViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var melliSubCategories = [String]()
var mazhabiSubCategories = [String]()
var sayerSubCategories = [String]()
#IBOutlet weak var melliButton: UIButton!
#IBOutlet weak var sayerButton: UIButton!
#IBOutlet weak var mazhabiButton: UIButton!
#IBAction func melliButtonClicked(_ sender: UIButton) {
categorySelected = 6
melliButton.isHighlighted = true
mazhabiButton.isHighlighted = false
sayerButton.isHighlighted = false
categoryTableView.reloadData()
}
#IBAction func sayerButtonClicked(_ sender: UIButton) {
categorySelected = 5
melliButton.isHighlighted = false
mazhabiButton.isHighlighted = false
sayerButton.isHighlighted = true
categoryTableView.reloadData()
}
#IBAction func mazhabiButtonClicked(_ sender: UIButton) {
categorySelected = 4
melliButton.isHighlighted = false
mazhabiButton.isHighlighted = true
sayerButton.isHighlighted = false
categoryTableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
categoryTableView.dataSource = self
categoryTableView.delegate = self
categoryTableView.register(CategorySelectTableViewCell.self, forCellReuseIdentifier: "Cell")
melliSubCategories = DataBaseManager.shared.subCategories(6)
mazhabiSubCategories = DataBaseManager.shared.subCategories(4)
sayerSubCategories = DataBaseManager.shared.subCategories(5)
print(melliSubCategories)
print("/////////////////")
print(mazhabiSubCategories)
print("/////////////////")
print(sayerSubCategories)
print("/////////////////")
}
#IBOutlet weak var categoryTableView: UITableView!
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch categorySelected {
case 4: //mazhabi
return mazhabiSubCategories.count
case 5: //sayer
return sayerSubCategories.count
case 6: //melli
return melliSubCategories.count
default:
return melliSubCategories.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! CategorySelectTableViewCell
cell.label?.text = melliSubCategories[indexPath.row]
return cell
}
And I create a class named CategorySelectTableViewCell for cells in table view that they have an image and a label.
In code I fill the arrays by database and I want to show them in the table view but the tableview doesn't show anything.
the screenshot : my storyboard, demo
You are saying:
cell.label?.text = melliSubCategories[indexPath.row]
It is impossible for this to work. For it to work, your custom cell type CategorySelectTableViewCell would need to be in a nib with a label outlet. But then that nib is either in a storyboard or a xib file. But you are also saying
categoryTableView.register(CategorySelectTableViewCell.self, ...
That line prevents the cell from coming from the xib or the storyboard. So the outlet cannot work and the cell will remain empty.
Please check array count is Zero or not in below numberOfRowsInSection method.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
Also, cross-check cell identifier is correct or not.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell : CategorySelectTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! CategorySelectTableViewCell
cell.label?.text = melliSubCategories[indexPath.row]
return cell
}
Reload tableview in ViewDidLoad method:
categoryTableView.reloadData()
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
categoryTableView.dataSource = self
categoryTableView.delegate = self
categoryTableView.register(CategorySelectTableViewCell.self, forCellReuseIdentifier: "Cell")
melliSubCategories = DataBaseManager.shared.subCategories(6)
mazhabiSubCategories = DataBaseManager.shared.subCategories(4)
sayerSubCategories = DataBaseManager.shared.subCategories(5)
print(melliSubCategories)
print("/////////////////")
print(mazhabiSubCategories)
print("/////////////////")
print(sayerSubCategories)
print("/////////////////")
categoryTableView.reloadData()
}

Action button not working within UITable

I have been through few of these tutorial and I cant seem to call my function via button click. I have followed this guy's tutorial but nothing works.
My tableView currently working just great, all Im doing now is adding a button so I could pass data to another view but my button click is not calling its function.
//class IncomeFeedCell: UITableViewCell:
#IBOutlet var weak button: UIButton!
View Contoller:
// class IncomeFeedVC: UIViewController, UITableViewDelegate, UITableViewDataSource:
// viewDidLoad:
tableView.delegate = self
tableView.dataSource = self
// cellForRowAt indexPath
let cell = self.tableView.dequeueReusableCell(withIdentifier: "IncomeFeedCell") as! IncomeFeedCell
cell.button.tag = indexPath.row
cell.button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
cell.configureCell(income: income)
return cell
Now the function to call when tapped:
func buttonPressed(){
print("Tapped")
}
Simulator:
Have I missed something simple?
Edit:
Apologies for all who and tried to help and got downvoted because I left out more vital information. All this is inside my viewDidLoad in IncomeFeedVC:
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
DataService.ds.REF_INCOMES.queryOrdered(byChild: "date").observe(.value, with: { (snapshot) in
/**
* Sorting the object before looping over
* Info here: http://stackoverflow.com/questions/41416359/sort-firebase-data-with-queryordered-by-date
*/
guard let incomeSnap = snapshot.value as? [String:AnyObject] else{
return
}
let sorted = incomeSnap.sorted{($0.0.value["date"] as! Double) > ($0.1.value["date"] as! Double)}
for snap in sorted {
if let incomeDict = snap.value as? [String: AnyObject] {
let key = snap.key
let income = Income(incomeId: key, incomeData: incomeDict)
self.incomes.append(income)
}
}
self.tableView.reloadData()
})
My ViewController:
class ViewController: UIViewController , UITableViewDelegate,UITableViewDataSource{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")! as! TestTableViewCell
cell.bttn.addTarget(self, action: #selector(clickme(sender:)), for: .touchUpInside)
return cell
}
func clickme(sender: UIButton) {
print("cliked")
}
}
My UITableViewCell
import UIKit
class TestTableViewCell: UITableViewCell {
#IBOutlet weak var bttn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Its working fine in my case.
Can you remove the "self" in your
let cell = self.tableView.dequeueReusableCell(withIdentifier: "IncomeFeedCell") as! IncomeFeedCell line.
your button tapped function should be like this:
func buttonPressed(sender: UIButton)
{
let buttonTag = sender.tag// you can check tag like this
}
Can you please try
cell.button.addTarget(self, action: #selector(IncomeFeedVC.buttonPressed(_:)), for: .touchUpInside)
Also below function should be implemented in IncomeFeedVC class
func buttonPressed(_ sender: AnyObject){
print("Tapped")
}

Why my Tableview is reusing some cells?

I have a Todo list, i have a label and a button in the same cell, when i click the button, change the image button for that cell, but when i scrolled the table view the same button appears on the others cells, it was not to appear in cells that the button were not pressed.
Here is my cellForRowAtIndexPath code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TaskTableViewCell
cell.label.text = "Task Number: \(indexPath.row + 1)"
cell.btnFavorite.setImage(UIImage(named: "star"), forState: .Normal)
cell.btnFavorite.setImage(UIImage(named: "star-filled"), forState: .Selected)
cell.btnFavorite.addTarget(self, action: #selector(ListOfTasksViewController.addRemoveFavoriteList), forControlEvents: .TouchUpInside)
return cell
}
func addRemoveFavoriteList(sender : UIButton) {
sender.selected = !sender.selected
}
Custom TableViewCell Class:
import UIKit
class TaskTableViewCell: UITableViewCell {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var btnFavorite: FavoriteButton!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
super.prepareForReuse()
label.text = nil
btnFavorite.selected = false
}
}
View Controller:
import UIKit
class ListOfTasksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TaskTableViewCell
cell.label.text = "Task Number: \(indexPath.row + 1)"
cell.btnFavorite.indexPath = indexPath.row
cell.btnFavorite.addTarget(self, action: #selector(ListOfTasksViewController.addRemoveFavoriteList), forControlEvents: .TouchUpInside)
return cell
}
func addRemoveFavoriteList(sender : FavoriteButton) {
if sender.selected {
sender.selected = false
} else {
sender.selected = true
let index = NSIndexPath(forRow: sender.indexPath, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(index) as! TaskTableViewCell
}
}
}
The cells in your table view are reused so as you scroll down, the cells going off screen are being put at the start of the queue before going back onto the screen at a different indexPath. This can cause some issues so you need to override the prepareForReuse method in your custom cell class.
override func prepareForReuse() {
super.prepareForReuse()
label.text = nil
btnFavorite.selected = false
}
you need to add condition in the cellforaRowAtIndexPath.
you need to add flag in Array which track your selection.
then its check in cellforRowAtIndexPath.
for example
button.selected= No
if arrselectedIndexpath containObject:indexPath{
button.selected =yes
}

Resources