didSelectRowAtIndexPath not working, Swift 3 - ios

Can anyone see why in the world didSelectRowAtIndexPath would not be called? I have triple checked by delegate both in the code and in storyboard.
class AddCard: UIViewController,UIPopoverPresentationControllerDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var cardView: UIView!
#IBOutlet weak var tableView: UITableView!
let tableItems = ["Background Color","Background Image","Font Style","Font Color"]
let cellID = "cell"
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setBackgroundColor (_ color: UIColor) {
cardView.backgroundColor = color
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath as IndexPath)
let row = indexPath.row
cell.textLabel?.text = tableItems[row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
print(indexPath.row)
let row = indexPath.row
switch(row){
case 0:
let popoverVC = storyboard?.instantiateViewController(withIdentifier: "colorPickerVC") as! ColorPickerViewController
popoverVC.modalPresentationStyle = .popover
popoverVC.preferredContentSize = CGSize(width: 284, height: 446)
if let popoverController = popoverVC.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: 0, y: 0, width: 85, height: 30)
popoverController.permittedArrowDirections = .any
popoverController.delegate = self
popoverVC.delegate = self
}
present(popoverVC, animated: true, completion: nil)
break
default: break
}
}
}

Swift 3 modified the signature of the method (a lot of methods too, new "rules"/style)
Replace:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) with
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Notice the _, the didSelectRowAt vs didSelectRowAtIndexPath, like the other ones you updated (which adapted also the same "style"), but not this one.
Remove the line and let XCode do the autocompletion. Else, you can just replace it with the one from the doc.

Related

How to customize UITableView and its cell to get clear color separator and different length of the cell depends on the title?

So far I have 7 tableview cells with no separator and fixed length for all of them. How do 1) add some clear color separators in between them and 2) set the cells background color to orange but the color should only be under the label which the text will have different length?
Here is my current code:
class CafesView: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let cafes = [
"Banana Joe's",
"College Eight Cafe",
"Global Village",
"Iveta",
"Stevenson Coffee House",
"Terra Fresca",
"Vivas"
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 7
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cafesCell = tableView.dequeueReusableCell(withIdentifier: "cafeCell", for: indexPath)
cafesCell.textLabel?.text = cafes[indexPath.row]
return cafesCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.frame.height / 7
}
#IBAction func closeTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}
class TableViewCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
self.backgroundColor = .systemOrange
self.roundCorners(corners: [.topLeft, .bottomLeft], radius: 10)
}
}
Add this line to remove separator line
tableView.separatorStyle = .none
And, add one label (here i added lblCafes) in UITableViewCell and set label background color to orange color.
Your code will be,
class CafesView: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let cafes = [
"Banana Joe's",
"College Eight Cafe",
"Global Village",
"Iveta",
"Stevenson Coffee House",
"Terra Fresca",
"Vivas"
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.separatorStyle = .none
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 7
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cafesCell = tableView.dequeueReusableCell(withIdentifier: "cafeCell", for: indexPath) as? TableViewCell
cafesCell?.lblCafes?.text = cafes[indexPath.row]
return cafesCell ?? UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.frame.height / 7
}
#IBAction func closeTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}
class TableViewCell: UITableViewCell {
#IBOutlet weak var lblCafes: UILabel!
override func layoutSubviews() {
super.layoutSubviews()
self.lblCafes.backgroundColor = .systemOrange
self.roundCorners(corners: [.topLeft, .bottomLeft], radius: 10)
}
}

reloadData() calls cellForRowAtIndexPath for every cell

So I'm having this issue that when reloadData() is called after the initial API call, it calls willDisplayCell method which when the last cell is displayed will load more data (API returns 10 data at a time).
However in the view it can show only 4 - 5 cells as I set the row height to 175 points manually. Does anyone know why is this happening?
If this is how the tableView works what can I do to make my tableView to load only 10 initially?
Following is my code.
class MainViewController: UIViewController {
var tableView: UITableView!
var photoViewmodel: PhotoViewModel!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Home"
initTableView()
photoViewmodel = PhotoViewModel()
photoViewmodel.loadNewPhotos {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
func initTableView() {
tableView = UITableView.init(frame: self.view.frame, style: .plain)
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 175
tableView.separatorStyle = .none
tableView.register(HomeTableViewCell.nib, forCellReuseIdentifier: HomeTableViewCell.identifier)
view.addSubview(tableView)
}
}
extension MainViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return photoViewmodel.photos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("cellForRowAt")
let cell = tableView.dequeueReusableCell(withIdentifier: HomeTableViewCell.identifier, for: indexPath) as! HomeTableViewCell
cell.tag = indexPath.row
cell.configureCell(url: photoViewmodel.photos[indexPath.row].regularImgUrl, cacheKey: indexPath.row)
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print("willDisplay")
let lastCell = photoViewmodel.photos.count - 1
if indexPath.row == lastCell {
print("add 10 more photos")
photoViewmodel.loadNewPhotos(
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
}
}

Button's Image is not changing even though the code for changing image is executed

I have a UICollectionView.
Inside each UICollectionViewCell of UICollectionView, I have a UITableView.
Inside each UITableViewCell of UITableView, I have a UIButton.
When clicking on UIButton or UITableViewCell, I want to change the image of UIButton.
Here is my UICollectionView:
Here is my code:
SurveyQuestionsCollectionViewController.swift
import UIKit
class SurveyQuestionCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var survey_questions: [Dictionary<String, Any>] = []
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView?.register(UINib.init(nibName: "SurveyQuestionsCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "survey_cell")
let layout = self.collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
let collectionViewSize = self.collectionView?.frame.size
let itemWidth = Int((collectionViewSize?.width)!)
let itemHeight = Int((collectionViewSize?.height)!)
layout.itemSize = CGSize(width: itemWidth, height: itemHeight)
common()
//result is coming from API call which I have deleted as it is not necessary to describe my problem
self.survey_questions = result["survey_questions"] as! [Dictionary<String, Any>]
self.collectionView?.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
common()
return survey_questions.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var question = survey_questions[indexPath.item]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "survey_cell", for: indexPath) as! SurveyQuestionsCollectionViewCell
cell.setValues(question: question["question"]! as! String,
answers: question["answers"]! as! [Dictionary<String, Any>])
return cell
}
func common() {
self.collectionView.setContentOffset(CGPoint(x: CGFloat(currentPosition) * self.collectionView.frame.size.width, y: 0), animated: true)
}
}
Here is my UICollectionViewCell and UITableView:
SurveyQuestionsCollectionViewCell.swift (at the back of .xib file)
import UIKit
class SurveyQuestionsCollectionViewCell: UICollectionViewCell, UITableViewDataSource, UITableViewDelegate {
var answers: [Dictionary<String, Any>] = []
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var tableView: UITableView!
override func layoutSubviews() {
super.layoutSubviews()
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView?.register(UINib.init(nibName: "SurveyQuestionsTableViewCell", bundle: nil), forCellReuseIdentifier: "survey_answer_cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return answers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let answer = answers[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "survey_answer_cell", for: indexPath) as! SurveyQuestionsTableViewCell
cell.setRadioText(text: answer["answer"]! as! String)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "survey_answer_cell", for: indexPath) as! SurveyQuestionsTableViewCell
cell.setRadioImage(rowSelected: true, tableView: tableView)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "survey_answer_cell", for: indexPath) as! SurveyQuestionsTableViewCell
cell.setRadioImage(rowSelected: false, tableView: tableView)
}
func setValues(question: String, answers: [Dictionary<String, Any>]) {
self.questionLabel.text = question
self.answers = answers
self.tableView.reloadData()
}
}
Here is my TableViewCell
SurveyQuestionsTableViewCell.swift (at the back of .xib file)
import UIKit
class SurveyQuestionsTableViewCell: UITableViewCell {
#IBOutlet weak var radioButton: UIButton!
#IBOutlet weak var radioLabel: UILabel!
func setRadioText(text: String) {
radioLabel.text = text
}
func setRadioImage(rowSelected: Bool, tableView: UITableView) {
if rowSelected {
if let image = UIImage(named: "radioOn") as UIImage! {
self.radioButton.setImage(image, for: UIControlState.normal)
}
}
} else {
if let image = UIImage(named: "radioOff") as UIImage! {
self.radioButton.setImage(image, for: UIControlState.normal)
}
}
}
}
And here is my output:
Every time when I click on any TableCell, I would like to change the image of radioButton. But the image is not changing. I have also marked that code for changing image is executed but the image is not changing.
It's happening because you set cell.setRadioImage(rowSelected: false, tableView: tableView) code indidDeselectRowAtmethod look at your below code
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "survey_answer_cell", for: indexPath) as! SurveyQuestionsTableViewCell
cell.setRadioImage(rowSelected: false, tableView: tableView)
}
Just remove last line.
Updated :
For get cell in tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) you need write below line
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
// Your Stuff
let cell = tableView.cellForRow(at: indexPath) // Change this line
// Your Stuff
}
Instead of doing that much, follow the below step and do in short and clear.
Select your button and assign the image for its state.
a. for Default State
b. for Selected State
In SurveyQuestionsCollectionViewCell
var indexSelected : Int = 0
In cellForRowAt
if indexPath.row == indexSelected{
cell.button.isSelected = true
}
else{
cell.button.isSelected = false
}
in didSelectRowAt
self.indexSelected = indexPath.row
table.reloadData()
If still facing any issue then ask.

tableview cell not clicking

UITableViewCell sub class:
class MenuDrawerTableViewCell: UITableViewCell {
#IBOutlet weak var Label3: UILabel!
#IBOutlet weak var Image30: 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
}}
I have that class, now I got my viewController which has a table.
class OpenMenu: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableV: UITableView!
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
var selected = 0
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("prepare")
var DestVC = segue.destination as! CheckinController
var indexPath: NSIndexPath = self.tableV.indexPathForSelectedRow! as NSIndexPath
let menuItem = menuList[indexPath.row]
DestVC.varView = menuItem.index
}
let newSwiftColor = UIColor(red: CGFloat(255), green: CGFloat(0), blue: CGFloat(238), alpha: CGFloat(1))
var menuList = [Menu]()
func loadMenu() {
let photo1 = UIImage(named: "checkin")!
let menu1 = Menu(name: "Check In", photo: photo1, index: 20)!
let photo2 = UIImage(named: "checkin")!
let menu2 = Menu(name: "Add Store", photo: photo2, index: 10)!
menuList += [menu1, menu2]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuList.count // your number of cell here
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "MenuDrawerTableViewCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath as IndexPath) as! MenuDrawerTableViewCell
let menuItem = menuList[indexPath.row]
cell.Image30.image = menuItem.photo
cell.Label3.text = menuItem.name
cell.Label3.numberOfLines = 1;
if(0 == selected)
{
selected = 1
self.tableV.selectRow(at: indexPath, animated: true, scrollPosition: UITableViewScrollPosition.none)
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
// cell selected code here
print("cell selected")
print(indexPath)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MenuDrawerTableViewCell", for: indexPath as IndexPath) as UITableViewCell
return cell
}
#IBOutlet weak var Open: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
loadMenu()
self.tableV.delegate = self
self.tableV.dataSource = self
let size:CGFloat = 35.0 // 35.0 chosen arbitrarily
let preferences = UserDefaults.standard
let name1 = ""+preferences.string(forKey: "name")!
label2.text = name1
label1.text = String(name1[name1.startIndex])
label2.textColor = UIColor.white
label1.textColor = UIColor.white
label1.textAlignment = NSTextAlignment.center
label1.font = UIFont.systemFont(ofSize: 17)
label1.bounds = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: size, height: size))
label1.layer.cornerRadius = size / 2
label1.layer.borderWidth = 3.0
label1.layer.backgroundColor = newSwiftColor.cgColor
label1.layer.borderColor = UIColor.black.cgColor
}
override func viewDidAppear(_ animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}}
What I want, is detect the click on a tableview. But I am not able to detect anything .I supposedly should get cell selected printed, but i am getting nothing.Why the click function not getting called?
I think you need to selection of tableview as below :
You can check your code you have to implemented two time methods(cellForRowAtIndexPath and cellForRowAt)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
First make sure that you have connected tableview and connected delegate and datasource also.
Please remove these lines of code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MenuDrawerTableViewCell", for: indexPath as IndexPath) as UITableViewCell
return cell
}
As already you implemented this method.
Hope this will fix your problem.
I had this problem and noticed that somehow "isEditing" was set to "true" for the tableView in my viewDidLoad code... removing that line of code fixed it.

re-populating a tableview with new array elements when a cell is clicked in swift

thanks for all the help so far. I need, when a cell in UITableView is clicked, to re-populate the view with an array read from another class - just can find a way to refresh the view. Code as follows:
Thanks in advance - the help so far has been great for this newbie.
import UIKit
class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
let textCellIdentifier = "TextCell"
var catRet = XnYCategories.mainCats("main")
//var catRet = XnYCategories.subCats("Sport")
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
// MARK: UITextFieldDelegate Methods
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return catRet.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! UITableViewCell
let row = indexPath.row
cell.textLabel?.text = catRet[row]
return cell
}
// MARK: UITableViewDelegate Methods
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
//let currentCell = tableView.cellForRowAtIndexPath(indexPath)
//var selectedText = currentCell!.textLabel?.text
//println(selectedText)
let catRet2 = XnYCategories.mainCats(catRet[row])
println(catRet2)
println(catRet[row])
//catRet = catRet2
}
}
Call reloadData() on your tableView as follow
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
//let currentCell = tableView.cellForRowAtIndexPath(indexPath)
//var selectedText = currentCell!.textLabel?.text
//println(selectedText)
let catRet2 = XnYCategories.mainCats(catRet[row])
println(catRet2)
println(catRet[row])
// *** New code added ***
// remove the comment
catRet = catRet2
// call reloadData()
tableView.reloadData()
// *** New code added ***
}
just do this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
catRet = XnYCategories.mainCats(catRet[row])
tableView.reloadData()
}

Resources