scrollToRowAtIndexPath with UITableView does not work

43,115

Solution 1

The solution below worked for me. It's a combination of solutions found on StackOverflow. I called "scrollToRowAtIndexPath" after a very short delay.

func tableViewScrollToBottom(animated: Bool) {

    let delay = 0.1 * Double(NSEC_PER_SEC)
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

    dispatch_after(time, dispatch_get_main_queue(), {

        let numberOfSections = self.tableView.numberOfSections()
        let numberOfRows = self.tableView.numberOfRowsInSection(numberOfSections-1)

        if numberOfRows > 0 {
            let indexPath = NSIndexPath(forRow: numberOfRows-1, inSection: (numberOfSections-1))
            self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
        }

    })
}

called by :

tableViewScrollToBottom(true)

Swift 3

func tableViewScrollToBottom(animated: Bool) {
    DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
        let numberOfSections = self.tableView.numberOfSections
        let numberOfRows = self.tableView.numberOfRows(inSection: numberOfSections-1)

        if numberOfRows > 0 {
            let indexPath = IndexPath(row: numberOfRows-1, section: (numberOfSections-1))
            self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: animated)
        }
    }
}

Solution 2

The solution at my problem is:

let numberOfSections = tableView.numberOfSections()
let numberOfRows = tableView.numberOfRowsInSection(numberOfSections-1)

if numberOfRows > 0 {
    println(numberOfSections)
    let indexPath = NSIndexPath(forRow: numberOfRows-1, inSection: (numberOfSections-1))
    tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
}

Solution 3

SWIFT 3 VERSION of @Fox5150 answer, with an extension :

extension UITableView {

    func tableViewScrollToBottom(animated: Bool) {

        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {

            let numberOfSections = self.numberOfSections
            let numberOfRows = self.numberOfRows(inSection: numberOfSections-1)
            if numberOfRows > 0 {
                let indexPath = IndexPath(row: numberOfRows-1, section: (numberOfSections-1))
                self.scrollToRow(at: indexPath, at: UITableViewScrollPosition.bottom, animated: animated)
            }
        }
    }
}

USAGE:

self.tableView.tableViewScrollToBottom(animated: true)

Solution 4

Try reloading first before calling scroll. Very weired but works for iOS8.

   tableView.reloadData()
   tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)

Solution 5

I have the problem with a bigger index say even 15. Only indexes till 5-6 use to work. By making "animated: false" scrollToRowAtIndexPath() worked perfectly.

Share:
43,115

Related videos on Youtube

Kobazzo
Author by

Kobazzo

Updated on April 01, 2022

Comments

  • Kobazzo
    Kobazzo about 2 years

    I have in iOS8 a table view like this:

    tableView = UITableView(frame: view.bounds, style: .Plain)
    view.addSubview(tableView)
    

    When the user types and sends some text in the keyboard, the application ivoke the following method to scroll the tableView. The goal is to view the new text in the screen (like a chat)

    let numberOfRows = tableView.numberOfRowsInSection(0)
            if numberOfRows > 0 {
                let indexPath = NSIndexPath(forRow: numberOfRows-1, inSection: 0)
                tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
            }
    

    But the table view does not scroll to the bootom.

    Someone has a solution?

    Thank you.

    Explanation:

    Definition of the class:

    class ChatViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextViewDelegate 
    

    then I have the definition of the table view:

    var tableView: UITableView! 
    

    in viewDidLoad:

    tableView = UITableView(frame: view.bounds, style: .Plain) 
    tableView.dataSource = self 
    tableView.delegate = self 
    view.addSubview(tableView) 
    

    then I have the call to the code that should make the scroll (second block of code on my answer). When I launch the application I expect the tableview to scroll down, but it does not work.

  • Kobazzo
    Kobazzo over 9 years
    Thank you, later i'll try this solution.
  • fluidsonic
    fluidsonic over 9 years
    A little more context is necessary then. Can you share more code please?
  • Kobazzo
    Kobazzo over 9 years
    Definition of the class: class ChatViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextViewDelegate the definition of the table view: var tableView: UITableView! in viewDidLoad: tableView = UITableView(frame: view.bounds, style: .Plain) tableView.dataSource = self tableView.delegate = self view.addSubview(tableView) ... cal to the code that sould make the scroll (second block of code on my answer). When I launch the application I expect the tableview scrolls down, but does not work
  • fluidsonic
    fluidsonic over 9 years
    Please edit your original question to add new code. This is barely readable.
  • fluidsonic
    fluidsonic over 9 years
    This is still not enough code to understand how and when you scroll to the last cell. Can you show the whole process from the point where the message is added until the scroll happens (which you already posted)? -- You should also check out SlackTextViewController - maybe you find it helpful as it seems to do what you're looking for.
  • Manuel
    Manuel over 8 years
    This is the best solution I found so far. I had to increase the delay to 0.5 though otherwise it would sometimes be called before tableView.reloadData has finished. I tried about every solution on SO (subclass TableViewDelegate and override reloadData; execute on main thread with dispatch_asynch, etc.) to scroll to bottom, none of them seem to work anymore for iOS 9.
  • jcady
    jcady over 8 years
    iOS 9 broke other methods for scrolling to the bottom of a table. But this one works.
  • nmdias
    nmdias about 8 years
    I needed to update a table view's scroll position that isn't visible when the scroll is taking place and this worked for me. Tested on iOS9. Also, It's not that it didn't scroll, but it didn't scroll completely in all instances. Now it does.
  • jose920405
    jose920405 about 8 years
    cause crash in let numberOfRows = tableView.numberOfRowsInSection(numberOfSections-1) if numberOfSections is 0
  • iOS_Developer
    iOS_Developer about 7 years
    This didn't help me ....I have to scroll manually to see the contents for last row. there is nothing wrong with table view and its content size because manual scroll shows the contents properly.
  • MEnnabah
    MEnnabah almost 7 years
    This is not scrolling at all. And please, check the code as you're not using the arguments parentheses in your func
  • Evgeniy Kleban
    Evgeniy Kleban over 6 years
    It works but i wonder if there is any way to do this without dispatch after?
  • Antoine Rucquoy
    Antoine Rucquoy over 5 years
    WHAT IS THIS SORCERY
  • Luke
    Luke almost 5 years
    Using "DispatchQueue" worked for me too in 2019, with Swift 5. scrollToRow was not working without delaying it by using "DispatchQueue". Can someone please explain its reason? Why a delay is necessary?
  • SleepNot
    SleepNot about 4 years
    scrollToRow is one of the most frustrating things to use in iOS. I am already adding a delay but sometimes it doesn't scroll all the way through the bottom.
  • Ankush Bhatia
    Ankush Bhatia about 4 years
    I will never support this solution as blocking main thread simply does not mean that we are just blocking UI, we might be blocking something else running on that queue.
  • Dave Y
    Dave Y almost 4 years
    Works in 2020 for my related issue - thanks for the idea! For info I had some bad behaviour when scrolling to a position during a scrollView bounce. i.e. if the scrollView is still offset from a scroll bounce, jumping to a certain scroll position can misbehave. Delaying the scrollToRow by 100ms cleaned this up. Perfecto.