I saw multiple threads on selecting the first row by default in a UITableViewController with a NavigationController, and I used some of the code I found via some of the communities answers, but it's still not working for me.
override func viewDidAppear(_ animated: Bool) {
let indexPath = IndexPath(row: 0, section: 0)
tableView.selectRow(at: indexPath as IndexPath, animated: false, scrollPosition: .middle)
}
It just highlights any row I put as the indexPath, but it doesn't actually go to the view associated with that indexPath. I feel like it's connected right though, because when I do actually click the row it goes to the view. Am I missing a step here?
Thanks in advance!
Calling this method does not cause the delegate to receive a
tableView(:willSelectRowAt:) or tableView(:didSelectRowAt:) message,
nor does it send UITableViewSelectionDidChange notifications to
observers.
You must call UITableview's delegate didSelectRowAt method.
Related
I have a TableView with a playlist of music tracks. When I click on the row, the track starts to play and the current row is selected. Also, I have a search bar, which works fine. But if I click on the row, then on the search bar and then I finally on the Cancel button - the row with the current track is not selected. In other situations, like forward or backward playback, the selection of rows works well.
Simplified, my code looks like this:
class TableView: UIViewController, UISearchResaultUpdating, UISearchBarDelegate {
...
private var currentSelectedRowIndex = 0
func ...didSelectRowAt indexPath... {
...
currentSelectedRowIndex = indexPath.row
print(currentSelectedRowIndex)
}
...
func searchCancelButtonClicked... {
print("Cancel button pressed")
print(currentSelectedRowIndex)
tableView.selectRow(at: IndexPath(row: currentSelectedRowIndex, section 0), animated: true, scrollPosition: .middle)
}
}
//For example, I pressed second row
Console message:
1
Cancel button pressed
1
==========================
But the row is not selected, what's the problem?
If you look at the UITableView documentation, it clearly says that calling selectRow does not cause the delegate to receive tableView(_:didSelectRowAt:).
You can move whatever you are doing in tableView(_:didSelectRowAt:) to another function and call that function in tableView(_:didSelectRowAt:) and searchCancelButtonClicked.
Or you can use the following code to manually invoke tableView(_:didSelectRowAt:) in searchCancelButtonClicked.
func searchCancelButtonClicked() {
print("Cancel button pressed")
print(currentSelectedRowIndex)
let indexPath = IndexPath(row: currentSelectedRowIndex, section: 0)
yourTableViewOutlet.delegate?.tableView?(yourTableViewOutlet, didSelectRowAt: indexPath)
tableView.selectRow(at: indexPath, animated: true, scrollPosition: .middle)
}
I'm trying to get my TableView to scroll to the bottom before the user sees the TableView. Right now, I have it set up so that when the page loads, the user sees the TableView and then instantly sees it scroll to the bottom. I need it to be at the bottom beforehand, so the user doesn't have to see it scroll. Anyone know how to do this?
class ChatViewController: UIViewController, CNContactPickerDelegate, UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource, UIToolbarDelegate, UITextFieldDelegate, UITextViewDelegate {
func scrollToBottom() {
let numberOfSections = self.chatTableView.numberOfSections
let numberOfRows = self.chatTableView.numberOfRows(inSection: numberOfSections-1)
let indexPath = IndexPath(row: numberOfRows-1 , section: numberOfSections-1)
self.chatTableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.middle, animated: true)
}
override func viewDidAppear(_ animated: Bool) {
scrollToBottom()
}
}
EDIT 1:
Just to let you know what I've tried, I ran the method in viewWillAppear instead of viewDidLoad but that gave me an error. I think it has to do with the numberOfRows being dynamic and table having not loaded yet. I tried setting animation to false but that just makes the user see the page jump down fast, they're still seeing movement. I tried putting the method in the celForRow at so it might run after getting the messages but that didn't work. I have a method to retrieve the messages from a database and I tried putting my scrollToBottom method at the end of that but it didn't work either. I don't think it's just an issue of placement, I think there's something else I need to add but no one has been any help yet.
Do as this,
Call your method in viewWillAppear.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
scrollToBottom()
}
// make your animation as false in scrollToRow
func scrollToBottom() {
let numberOfSections = self.chatTableView.numberOfSections
let numberOfRows = self.chatTableView.numberOfRows(inSection: numberOfSections-1)
let indexPath = IndexPath(row: numberOfRows-1 , section: numberOfSections-1)
self.chatTableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.middle, animated: false)
}
I have a tableview list with clickable cells, when one is clicked a new viewcontroller opens up. When a back button is clicked and the first VC is called, the tableview resets to the top of the list. How can I change this so when the back button is clicked the tableview goes back to the original cell clicked? From what I understand, I need a tableview.scrollToRow, but I'm getting a little lost in the indexPath that I need to select (believe I need to save the last selected row, but now sure how to do this)
Here's the code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let webVC = UIStoryboard.init(name: "MainVC", bundle: nil).instantiateViewController(withIdentifier: "SecondaryVC") as! WebViewController
webVC.urlLink = self.listings?[indexPath.row].url
self.present(webVC, animated: true, completion: nil) }
override func viewWillAppear(_ animated: Bool) {
tableview.scrollToRow(at: indexPathSelected, at: .middle, animated: false)
}
Your problem is that you are actually moving forward to a new instance of your view controller rather than back to the existing instance. If you move back then the state of the view controller will be as you left it and there will be no need to do anything to the tableview.
You should use an unwind segue to move back
As your cell is respond to your touch(and you did not call deselectRow(at indexPath: IndexPath) after selecting cell), the tableView will keep your selection(s), so when you back to your viewController just call tableView.indexPathForSelectedRow(or tableView.indexPathsForSelectedRows) in your viewWillAppear() method.
I haven't coded this, but I am wondering if it is even possible and how it can be done. Let's say I am on VC1. If I press a button on VC1, I want to be taken to VC2, which has a table view, and then have it automatically select the first cell and segue to a VC3. Anybody with experience of doing this.
Assuming this is more of a conceptual question, yes, this can be done. I've worked on an app where the feature required animating through multiple levels of table views programmatically using NSNotification's. Essentially, you can just have a shared method that is called from tableView:didSelectRowAtIndexPath: that you would call directly to "select" the table cell and do whatever the default action was.
Let me know if this answers your question.
Yes It can be done.There can be many ways, One way is this -
1.In Your viewDidAppear of VC2 have this lines -
override func viewDidAppear() {
super.viewDidAppear()
let rowToSelect:NSIndexPath = NSIndexPath(forRow: 0, inSection: 0)
tableView.selectRowAtIndexPath(rowToSelect, animated: true, scrollPosition: UITableViewScrollPosition.None)
self.tableView(tableView, didSelectRowAtIndexPath: rowToSelect)
}
In your tableView method didSelectRowAtIndexPath -
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
self.presentVC3()
}
}
func presentVC3() {
//Initialize VC3
// And Segue to VC3
}
I have a master detail layout with table views in both of the views. Left panel has a list of patients and right has a list of documents, what happens is by changing the patient selection documents will be reloaded and if the user clicks on a document, it will segue to a webView to display PDF.
For consistency purpose i made the first cell in the Patient table to be selected by default using the below code
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
let rowToSelect:NSIndexPath = NSIndexPath(forRow: 0, inSection: 0);
self.tableView.selectRowAtIndexPath(rowToSelect, animated: true, scrollPosition: UITableViewScrollPosition.None)
self.performSegueWithIdentifier("showDetail", sender: self)
}
work's fine right?, Yes but it gets a bit inconsistent from here, after closing this PDF document (by clicking done on navigation), my Previously selected cell will go off and it again points to the first Patient. Is there any way to save this selection? Oh and even to save the selection on the details page too. Thanks.
Create an NSIndexPath property.
Change your viewDidAppear to only default-select the first cell if there wasn't something previously selected:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
if (!self.rowToSelect) {
rowToSelect = NSIndexPath(forRow: 0, inSection: 0);
self.tableView.selectRowAtIndexPath(rowToSelect, animated: true, scrollPosition: UITableViewScrollPosition.None)
self.performSegueWithIdentifier("showDetail", sender: self)
}
}
In the didSelectRow delegate method store the selected index path in self.rowToSelect.