I've been going in circles for a while and nothing I've found in related posts seems to solve it.
I'm programmatically adding a table to a custom UIView. The table and row text displays correctly, but neither didSelectRowAtIndexPath nor willdSelectRowAtIndexPath fire when I run this on the simulator and try to click on any of the rows.
The relevant bits of my code below:
import UIKit
import AVFoundation
#IBDesignable
class PerformanceQuestionView: UIView, UITableViewDelegate, UITableViewDataSource {
var optionsTable = UITableView(frame: CGRectMake(10,200,250,200))
var optionItems = ["One", "Two", "Three", "Four"]
convenience init(rect: CGRect, performanceQuestion:PerformanceQuestion?) {
self.init(frame: rect)
NSLog("PerformanceQuestionView.init()")
self.optionsTable.dataSource = self
self.optionsTable.delegate = self
self.optionsTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.optionsTable.allowsSelection = true
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
NSLog("numberOfRowsInSection")
return optionItems.count
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
NSLog("cellForRowAtIndexPath")
var cell:UITableViewCell = self.optionsTable.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel.text = self.optionItems[indexPath.row]
return cell
}
func tableView(tableView: UITableView!, willSelectRowAtIndexPath indexPath: NSIndexPath!) -> NSIndexPath! {
NSLog("You will select cell #\(indexPath.row)!")
return indexPath
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
NSLog("You selected cell #\(indexPath.row)!")
}
override func layoutSubviews() {
super.layoutSubviews()
self.addSubview(optionsTable)
}
}
Removing the TapGestureRecognizer worked for me!!!
// var backgoroundTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "DismissKeyboard")
// self.view.addGestureRecognizer(backgoroundTap)
Reason for this could be, you are using a pan gesture in the view. like AAA mentioned removing your pan gesture will do the trick. But if you still want to use the pan gesture you could do the following
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)
tap.cancelsTouchesInView = false
Making cancelsTouchesInView, false will enable all you taps.
Remove the exclamation points:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
You need to add below code for Tap or Pan gesture.You need to tap.cancelsTouchesInView = false
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)
tap.cancelsTouchesInView = false
OR
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.mainBlurViewAction))
mainBlurView.addGestureRecognizer(gesture)
gesture.cancelsTouchesInView = false
Then it will work
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Call According requirement
}
I have the same problem long time, I am for thinking it's a bug in UITableView programmatically when creating a UIView class.
My temporary solution and although it is not a good idea, but it works. It is to place a button the size of the cell and have an action dispatched by a protocol, to achieve at least simulate this action.
It is not good practice but could not stay stuck there longer.
For Swift 3.0, you need to use this function exactly:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Input your code here
}
Look very closely to make sure you are using this function. The compiler won't complain if you have NSIndexPath or you don't have _ before tableView but it won't work. So use this function, put a breakpoint in and you will see it go to that point when you tap on a row.
I was testing this with a static table (all static content cells).
This was deprecated in Swift 3:
override func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
...
}
And replaced with:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
}
I tried all of the methods listed in this question and others. I finally deleted the table from my storyboard and started again.
In my storyboard, I added back the table, added a prototype cell. I connected the ViewController to the table. I connected the table to my dataSource and delegate methods.
I named the prototype identifier in the Attributes Inspector.
This worked for me. I did not apparently have any code to change.
Related
I'm new to iOS, swift. I have two sections in my tableView. I want to be able to do a longPressGesture on the second section, and not the first, enabling the user to reorder tableview cells in the second section. How would I do that in swift? Would anyone kindly provide a simple sample code in Swift?
Thanks for your help, much appreciated!
If you just want to reorder move the cell for the particular you may add some button/action to enable/disable reorder , there is delegate which you can use
Your code can be like this:
//enable editing in the tableview to true when you want to enable reorder in your case may on the UILongPressGestureRecognizer action
//In viewDidLoad()
tblView.editing = true//set it to false to complete the reorder
The delegate methods can be use like this:
func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.None
}
func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
//get the reorder change in the path, you can do operation on the array
let itemToMove:String = arrData[fromIndexPath.row]//get the old path of item
arrData.removeAtIndex(fromIndexPath.row)//remove item from old path
arrData.insert(itemToMove, atIndex: toIndexPath.row)//at item at new path in array
}
func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
//write code to allow reorder in the particular section/indexpath
if indexPath.section == 0 {
return false
} else {
return true
}
// Return false if you do not want the item to be re-orderable.
}
func tableView(tableView: UITableView, targetIndexPathForMoveFromRowAtIndexPath sourceIndexPath: NSIndexPath, toProposedIndexPath proposedDestinationIndexPath: NSIndexPath) -> NSIndexPath {
//check if the reorder is allow in the particular section/indexpath before the reorder is done, return the old path if you don't want to move at Proposed path
if sourceIndexPath.section != proposedDestinationIndexPath.section {
return sourceIndexPath
} else {
return proposedDestinationIndexPath
}
}
the UILongPressGestureRecognizer can be implemented on the tableview or the tableview cell based on the requirements
let longpress = UILongPressGestureRecognizer(target:self, action:#selector(HomeScreenTableViewController.longPressGestureRecognized))
tblView.addGestureRecognizer(longpress)
func longPressGestureRecognized() {
NSLog("Detected")
tblView.editing = true
}
or in tableview cell with same method as above
let longpress = UILongPressGestureRecognizer(target:self, action:#selector(HomeScreenTableViewController.longPressGestureRecognized))
cell.addGestureRecognizer(longpress)
I have strange behavior with UITableView on Storyboard today. I have created UITableView on Storyboard. After that I drag a PrototyleCell to this table and choose style is Basic. And I implement DataSource and Delegate on my ViewController. It show to simulator normal. But I can't tap to table for select a cell and didSelectCellAtIndexPath don't work too. In Storyboard I have checked selectionStyle. If I change style to another style, It work normally.
So my question is: this is a bug or it is a behavior of UITableView? And anyone can give some explanation for it.
Here is my code: Problem Cell Code. I can't select when use it but when I set another style of cell on storyboard everything will ok.
Thanks in advance
No its neither bug nor normal behavior, you must be doing some basic mistake...
Try following code with tableview and prototype cell in storyboard, Everthing will work.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var dataSource = ["Ajay","Ajay","Ajay","Ajay","Ajay","Ajay"]
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell?
if cell == nil {
cell = UITableViewCell(style: .Value1, reuseIdentifier: "cell")
}
cell!.textLabel?.text = dataSource[indexPath.row]
return cell!
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(indexPath.row)
} }
Have you added the
tableView: cellForRowAtIndexPath delegate method. This is a required delegate you must implement.
I have the following problem:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// ...
println(indexPath.row)
}
My output goes like this:
1
0
1
0
The numberOfRowsInSection tells me that I've got 10 items:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.actionDto != nil){
println(self.actionDto?.count)
return self.actionDto!.count
}
return 0
}
I have checked this indexpath.row is starting from 1 instead of 0? but can't really follow the answer or solve my problem.
Actually i just want to tap a Label in the cell and do some other stuff. But i have to know exactly which row it was.
I thought about using didSelectRowAtIndexPath method. Then i have problem that if i tap on the label the didSelectRowAtIndexPath method isn't called. (I think because of more than one observer on this label. -> i have delegate method on this cell and the other one i suppose is the tableview.)
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = tableView.indexPathForSelectedRow()
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! TimelineCell
println("The number of cell is \(currentCell.numberOfRowAtIndexPath)")
}
If i click into the cell but not on labels or images all works fine and i get the right number of row. Perhaps someone knows how i can add more than one "observer" on a label for example. So that my Selectormethod and didSelectRowAtIndexPath both knew about the label tapped in the cell. I think this could solve my problem that i can do my own Selectormethod with the knowledge of the right row.
For people who want to know what i mean with Selectormethod:
let gestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("labelPressed")) <-
label.addGestureRecognizer(gestureRecognizer)
func labelPressed() {
delegate?.switchToOwnProfil!()
}
The mysterious thing is, that the first output shows me first 1 and not 0 but perhaps i overlooked something.
Thanks in advance!
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// ...
yourLabel.tag = indexPath.row
let gestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("labelPressed:")) <-
yourLabel.addGestureRecognizer(gestureRecognizer)
println(indexPath.row)
}
and in your function
func labelPressed(label:UILable) {
println(label.tag)
delegate?.switchToOwnProfil!()
}
I have a custom UITableViewCell containing a UIActivityIndicatorView (spinner), and I try to click on the cell so that spinner starting to animate. So I try to implement following in UITableViewController:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier("testcase", forIndexPath: indexPath) as TestCaseTableViewCell
cell.spinner.startAnimating()
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
I have the instance variable "spinner" in my TestCaseTableViewCell(custom cell class):
#IBOutlet weak var spinner: UIActivityIndicatorView!
But it didn't work......
I just want to click on the cell, and the spinner starts to animate cause I want to do something in this period. While the something is done, I can show something like "OK" in the cell(as the same position of the spinner). How can I achieve that?
The problem is with how you are retrieving your cell from the table view: dequeueReusableCellWithIdentifier(identifier: String, forIndexPath indexPath: NSIndexPath). This method asks the UITableView for a cell from its reuse cache when you need a new cell to display, so should only be used in the tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) method of your table view's data source.
To ask the table view for an on-screen cell, use cellForRowAtIndexPath(indexPath: NSIndexPath). Your code sample then becomes:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) as? TestCaseTableViewCell {
cell.spinner.startAnimating()
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
Another simple method:
Select your UIActivityIndicatorView and check "Animating" in the attribute inspector
Check "hidden"
Now do this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier("testcase", forIndexPath: indexPath) as TestCaseTableViewCell
cell.spinner.hidden = false // <== Here
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
Don't forget to hide the unhidden UIActivityIndicatorView if needed ;)
New to IOS development and am having trouble with handling cell selection on a table. Whenever I select, the method is not getting called below - any idea why?
My project structure is:
View Controller -> View -> Table View
The below code demonstrates the method calls. The others get called no problem! I know touch is working as pull down successfully refreshes and on clicking a cell it does become highlighted.
import UIKit
class ViewController: UIViewController, UITableViewDelegate
{
let blah = ["blah1"]
//How many sections are in the table?
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
//How many rows? (returns and int)
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return blah.count
}
//table contents for each cell?
//Each time this is called it'll return the next row and thus build a table...
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("Populating each cell of table view!\n")
tableView.rowHeight = 80.0
var cell = UITableViewCell()
var(a) = blah[indexPath.row]
var image : UIImage = UIImage(named: a)!
cell.imageView.image = image
return cell
}
//Code Cell Selected
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
println("You selected cell #\(indexPath.row)!")
}
func tableView(tableView: UITableViewDelegate, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
print("wananananaanan" )
println("You deselected cell #\(indexPath.row)!")
}
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.
}
}
Everybody is mentioning to set dataSource and delegate of the tableView.
But after setting also not working fine then sometimes it may happen because of none or disable selection of table view.
To enable it
Go to storyboard -> Select tableView -> click on the attribute inspector ->go to selector -> Select selection as single selection (or multiple selection according to the requirements.)
Please find attached screenshot for your suitability.
You have to set an #IBOutlet to the tableView in you ViewController and set as it's delegate and dataSource to you can see the data an respond to changes in the tableView.
Something like this :
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
}
And implements the UITableViewDataSource protocol too.
Or you can too in the Interface Builder set the ViewController as it's delegate and dataSource (more easy to do I think) and avoid to set manually in code like above. Is up to you.
I hope this help you.
SWIFT 3
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Do here
}
Use the above delegate method in swift 3
Couple of checks that can help you:-
myTableView.allowsSelection = true
myTableView.delegate = self
Make sure you written didSelectRowAt correctly:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
If you are using UIButton on UITableViewCell then it overlaps cell so check Solution here
I faced the same issue when compared two identical code examples where one was working well and the other was not calling didSelectRowAtIndexPath
Take a look at two possible ways to solve the issue:
1) In the code itself:
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
table.delegate = self
table.dataSource = self
//data source might be already set if you see contents of the cells
//the main trick is to set delegate
}
2) Using Storyboard or Document Outline (which was the problem in my case cause storyboard changes are not visible in .swift controller classes.
Open Document Outline and Control + Press your TableView
you will see two outlets called "delegate" and "dataSource"
drag them 1 by 1 to the containing ViewController (right onto the yellow circle)
That's it!
Another caveat is tap gesture recognizers. It's a common use case to use tap gesture recognizer to handle different logic within your view controllers with table views, whether that's exiting touch control or first responders.
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
view.addGestureRecognizer(tapGesture)
E.G. This line of code handles dismissing a date picker in my application and prevents my tableview from calling didSelectRow delegate method
You have to use this: First take a look what are you extending and then use the tableView method.
class YourViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var mUITableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// We need to tell to UITableView that we will add the data by ourselves
self.mUITableView.delegate = self
self.mUITableView.dataSource = self
// Register the UITableViewCell class with the tableView
self.mUITableView?.registerClass(UITableViewCell.self, forCellReuseIdentifier: self.cellIdentifier)
// Setup table data
getEvents()
self.mUITableView.allowsSelection = true
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// here to create you cell view
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "subtitleCell")
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
cell.textLabel?.text = "\(tableData[indexPath.row].name) - (\(tableData[indexPath.row].eventStateId))"
cell.detailTextLabel?.text = tableData[indexPath.row].lastUpdate
return cell
}
}
Another reason you may write this function which allowed to click under condition
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
if(indexPath.section == 1){
return true
}
return false
}
Another caveat which took me ages to figure out is to make sure that all three of your Table View, your Cell and your Content View all have User Interaction Enabled. Then in Swift 4, at least, you can use:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
if you are editing your tableView:
tableView.allowsSelectionDuringEditing = true
Another thing to check is the access level for your class & method:
I had a Swift UIViewController class marked #objc public, to make it visible to my objective-c code.
In this context you must add public access to this function, or it will not be called.
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Nothing happened till I've cleaned and built again. :)