Basically, my table is displaying properly as what I would want it to be. However, when I click on my cell, it doesn't goes into my didSelectRowAtIndexPath method.
The below screenshot also doesn't show any preloaded didSelectRowAtIndexPath method.
My codes are as follows:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return personList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let myCell = stockTableView.dequeueReusableCellWithIdentifier("personCell", forIndexPath: indexPath) as UITableViewCell
myCell.textLabel?.text = personList[indexPath.row].personName
myCell.detailTextLabel?.text = personList[indexPath.row].GetPersonDescription()
return myCell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let myCell = stockTableView.dequeueReusableCellWithIdentifier("personCell", forIndexPath: indexPath) as UITableViewCell
let selectedCell = myCell.textLabel?.text
}
EDIT: After researching, I realised that I've not set my UITableViewDelegate protocol. I tried to find online but can't find any solution. Could someone help me with this?
// Set the UITableViewDataSource and UITableViewDelegate for your class
class YourClass: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.YourTableName.registerClass(UITableViewCell.self, forCellReuseIdentifier: "TotalsCell")
// Delegate and DataSource for your TableView
YourTableName.dataSource = self
YourTableName.delegate = self
}
}
Related
I am trying to create a simple todo list app for learning purposes i. I want to be able to click on a row and add a check mark and when clicked again i want it to go away. i have looked at several other examples but nothing is working. How can i achieve this?
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tbView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tbView.reloadData()
}
override func viewWillAppear(animated: Bool) {
self.tbView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return tasks.manager.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Default Tasks")
//Assign the contents of our var "items" to the textLabel of each cell
cell.textLabel!.text = tasks.manager[indexPath.row].name
cell.detailTextLabel!.text = tasks.manager[indexPath.row].time
return cell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath){
if (editingStyle == UITableViewCellEditingStyle.Delete){
tasks.manager.removeAtIndex(indexPath.row)
tbView.reloadData()
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell!.accessoryType = .Checkmark
tableView.reloadData()
}
}
To put it simply, you can use this code.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath)
if (cell!.accessoryType == .Checkmark) {
cell!.accessoryType = .None
} else {
cell!.accessoryType = .Checkmark
}
tableView.reloadData()
}
This way, when you re-select cell, the checkmark will adjust accordingly.
However, you shouldn't modify cell checkmark this way as the cell will get re used when you scroll.
You need to update your data model instead it above approach.
so in your data model, add new property to hold checkmark state and then use it in cellForRowAtIndexPath function.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Default Tasks")
//Assign the contents of our var "items" to the textLabel of each cell
cell.textLabel!.text = tasks.manager[indexPath.row].name
cell.detailTextLabel!.text = tasks.manager[indexPath.row].time
if tasks.manager[indexPath.row].isSelected { //assume that isSelected is bool
cell!.accessoryType = .Checkmark
} else {
cell!.accessoryType = .None
}
return cell
}
and then in your didSelectRowAtIndexPath update the model.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let dataModel = tasks.manager[indexPath.row]
dataModel.isSelected = !dataModel.isSelected
tableView.reloadData()
}
I'm assuming that you are using a table view in a storyboard. If that's the case, in the attributes inspector, you can choose a chick mark as the style.
You'll need both didSelectRowAtIndexPath and didDeselectRowAtIndexPath methods of the UITableViewDelegate protocol.
You can simple use them like this!
Deselect
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell!.accessoryType = .None
//tableView.reloadData()
}
Select
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell!.accessoryType = .Checkmark
//tableView.reloadData()
}
I have a TableViewController with static cells
I tried both creating segue from TableViewController and TableView cell (Not at the same time)
However, in both scenario, didSelectRowAtIndexPath was not fired
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("select")
}
I also have embedded collectionviewcontroller
class EventDetail: UITableViewController, UITextFieldDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
What may be causing this?
Check your tableview selection must be single selection, if it is "No selection" then didSelectedRowAtIndex would not get called.
You can download sample code and observe it.
Sample download
Also check
Ideally your cellForRowAtIndex should be like this
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell : CustomCell! = tableView.dequeueReusableCellWithIdentifier("ID_CustomCell", forIndexPath: indexPath) as! CustomCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
cell.lblData.text = "CustomCell....."
return cell
}
Swift 4 code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : CustomCell! = tableView.dequeueReusableCell(withIdentifier: "ID_CustomCell", for: indexPath) as! CustomCell
cell.selectionStyle = .none
cell.lblData.text = "CustomCell....."
return cell
}
call performseguewithidentifier from didselectRow if you have created segue from tableviewcontroller. like,
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("select")
self.performSegueWithIdentifier("your segue identifier", sender: self)
}
hope this will help :)
I have already asked this doubt/problem in SO. but not get get solution. Please help me out....
i have one table view which will show the list of name data till 10 datas. But what i need is , when user press any cell, that cell should be replace with another cell, which have some image, phone number, same data name. How to do that.
I have two xib : 1. normalcell, 2. expandable/replace cell
Here is my viewconrolelr.swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var Resultcount: UILabel!
var tableData = ["thomas", "Alva", "Edition", "sath", "mallko", "techno park",... till 10 data]
let cellSpacingHeight: CGFloat = 5
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var nib = UINib(nibName:"customCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
Resultcount.text = "\(tableData.count) Results"
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.tableData.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return cellSpacingHeight
}
// Make the background color show through
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.clearColor()
return headerView
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:customCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! customCell
cell.vendorName.text = tableData[indexPath.section]
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Starting my cell will look like this :
When i press that cell, i need some thing to do like this with replace ment of like below cell :
But when i press same cell again, again it should go to normal cell.
How to do that ??
First modify your tableView:cellForRowAtIndexPath: implementation as follows. Then you need to implement the click handler. One way would be in the MyCell class. Another would be to override selectRowAtIndexPath. Without knowing more about what you want (e.g. multiple vs single selection), it's hard to give actual code but here's something.
BOOL clickedRows[MAX_ROWS]; // Init this array as all false in your init method. It would be better to use NSMutableArray or something similar...
// selectRowAtIndexPath code
int row = indexPath.row
if(clickedRows[row]) clickedRows[row]=NO; // we reverse the selection for the row
else clickedRows[row]=YES;
[self.tableView reloadData];
// cellForRowAt... code
MyCell *cell = [tableView dequeueResuableCell...
if(cell.clicked) { // Nice Nib
[tableView registerNib:[UINib nibWithNibName... for CellReuse...
} else { // Grey Nib
[tableView registerNib:[UINib nibWithNibName... for CellReuse...
}
You need to create two independent cell on xib. Then you can load using check.You can copy and paste it will work perfectly.
in cellForRowAt like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if selectedIndexPath == indexPath && self.isExpand == true{
let cell = tableView.dequeueReusableCell(withIdentifier: "LeaveBalanceExpandedCell", for: indexPath) as! LeaveBalanceExpandedCell
cell.delegate = self
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "LeaveBalanceNormalCell", for: indexPath) as! LeaveBalanceNormalCell
return cell
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// cell.animateCell(cell)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedIndexPath == indexPath{
if isExpand == true{
self.isExpand = false
}
else{
self.isExpand = true
}
}
else{
selectedIndexPath = indexPath
self.isExpand = true
}
self.tableView.reloadData()
}
I've added TableView to my controller and created custom UITableViewCell. Later, I've tried to run this code:
func tableView(educationTableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> educationCell {
let cell:educationCell = educationTableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! educationCell
print("TableView runs")
return cell
}
but I do not get my print in logs TableView runs. I do not understand what happens and why it doesn't run. Who knows, why this problem appears?
I read other answers in SO, but noone helps =/
need the return value of numberOfRowsInSection greater than 0
Just make sure you have implemented proper DataSource and Delegate for controller, number of rows is greater then 0
import UIKit
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var items: [String] = ["We", "Heart", "Swift"]
#IBOutlet var tableView: UITableView! //hook this to your storyboard tableview
// MARK: - Controller life cycle stack
override func viewDidLoad() {
super.viewDidLoad()
//confirm table's delegate and data source programmatically
tableView.delegate = self;
tableView.dataSource = self;
}
//table view delegate and data source methods
func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int
{
//number of rows must be greater then 0 to get called "CellForRowAtIndex"
return self.items.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! CraditCardCell
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
print("You selected cell");
}
}
One reason could be because you modified the return type to educationCell, instdead of the standard UITableViewCell. Try changing that.
So i am trying to get the value of the textLabel of the row I select. I tried printing it, but it didn't work. After some research I found out that this code worked, but only in Objective-C;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"did select and the text is %#",[tableView cellForRowAtIndexPath:indexPath].textLabel.text);]
}
I could not find any solution for Swift. Printing the indexpath.row is possible though, but that is not what I need.
so what should I do? or what is the 'Swift-version' of this code?
Try this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = tableView.indexPathForSelectedRow() //optional, to get from any UIButton for example
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell
print(currentCell.textLabel!.text)
If you're in a class inherited from UITableViewController, then this is the swift version:
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell = self.tableView.cellForRowAtIndexPath(indexPath)
NSLog("did select and the text is \(cell?.textLabel?.text)")
}
Note that cell is an optional, so it must be unwrapped - and the same for textLabel. If any of the 2 is nil (unlikely to happen, because the method is called with a valid index path), if you want to be sure that a valid value is printed, then you should check that both cell and textLabel are both not nil:
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell = self.tableView.cellForRowAtIndexPath(indexPath)
let text = cell?.textLabel?.text
if let text = text {
NSLog("did select and the text is \(text)")
}
}
Swift 4
To get the label of the selected row:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
print(cell.textLabel?.text)
}
To get the label of the deselected row:
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
print(cell.textLabel?.text)
}
If you want to print the text of a UITableViewCell according to its matching NSIndexPath, you have to use UITableViewDelegate's tableView:didSelectRowAtIndexPath: method and get a reference of the selected UITableViewCell with UITableView's cellForRowAtIndexPath: method.
For example:
import UIKit
class TableViewController: UITableViewController {
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
switch indexPath.row {
case 0: cell.textLabel?.text = "Bike"
case 1: cell.textLabel?.text = "Car"
case 2: cell.textLabel?.text = "Ball"
default: cell.textLabel?.text = "Boat"
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell = tableView.cellForRowAtIndexPath(indexPath)
print(selectedCell?.textLabel?.text)
// this will print Optional("Bike") if indexPath.row == 0
}
}
However, for many reasons, I would not encourage you to use the previous code. Your UITableViewCell should only be responsible for displaying some content given by a model. In most cases, what you want is to print the content of your model (could be an Array of String) according to a NSIndexPath. By doing things like this, you will separate each element's responsibilities.
Thereby, this is what I would recommend:
import UIKit
class TableViewController: UITableViewController {
let toysArray = ["Bike", "Car", "Ball", "Boat"]
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return toysArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
cell.textLabel?.text = toysArray[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let toy = toysArray[indexPath.row]
print(toy)
// this will print "Bike" if indexPath.row == 0
}
}
As you can see, with this code, you don't have to deal with optionals and don't even need to get a reference of the matching UITableViewCell inside tableView:didSelectRowAtIndexPath: in order to print the desired text.
In my case I made small changes, when i search the value in tabelview select (didSelectRowAtIndexPath) the cell its return the index of the cell so im get problem in move one viewControler to another.By using this method i found a solution to redirect to a new viewControler
let indexPath = tableView.indexPathForSelectedRow!
let currentCellValue = tableView.cellForRow(at: indexPath!)! as UITableViewCell
let textLabelText = currentCellValue.textLabel!.text
print(textLabelText)
In swift 4 :
by overriding method
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name : "Main", bundle: nil)
let next vc = storyboard.instantiateViewController(withIdentifier: "nextvcIdentifier") as! NextViewController
self.navigationController?.pushViewController(prayerVC, animated: true)
}
This will work:
let item = tableView.cellForRowAtIndexPath(indexPath)!.textLabel!.text!
Maintain an array which stores data in the cellforindexPath method itself :-
[arryname objectAtIndex:indexPath.row];
Using same code in the didselectaAtIndexPath method too.. Good luck :)