9

How do I start a UITableView scrolled to the last cell?

  • not animated
  • not after view appeared
  • not after table view is even added as a subview

just have a plain UITableView(frame: CGRectZero, style: UITableViewStyle.Plain) that when presented on screen, will start scrolled all the way to the bottom.

I've tried:

// 1
reloadData()
scrollToRowAtIndexPath(
    NSIndexPath(forItem: dataArray.count-1, inSection: 0),
    atScrollPosition: .Top, animated: false
)

// 2
reloadData()
var contentOffset = self.contentOffset
contentOffset.y = CGFloat.max
setContentOffset(contentOffset, animated: false)

on the tableView's init method (in my subclass)

I've also tried the classic CGAffineTransformMakeScale(1,-1) hack, but that makes my cells stick to the bottom and I want them stuck the the top (but scrolled to the bottom). (that is only relevant if I have few cells, when they don't fill the entire UITableView space)

EDIT: another detail, I'm using dynamic cells UITableViewAutomaticDimension.

Rodrigo Ruiz
  • 4,248
  • 6
  • 43
  • 75
  • Refer to https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScrollView_Class/index.html#//apple_ref/occ/instm/UIScrollView/setContentOffset:animated: I think that is what you are looking for. Just set animated to false. – Kendel Aug 28 '16 at 22:48
  • For the 1st one, try setting the atScrollPosition to .Bottom. – Pranav Wadhwa Aug 28 '16 at 23:12
  • just call `tableView.setContentOffset(CGPointMake(0, CGFloat.max), animated: false)` in `viewDidLoad`. – Ozgur Vatansever Aug 29 '16 at 00:46
  • @Kendel that's my second attempt. @penatheboss tried =/. @ozgur I don't have a `viewDidLoad` here, I'm using just a `UITableView` that will be added to another view that is already loaded (but just to discard the possibility, I also had that same code using a regular `UITableViewController` and still get the same problem). – Rodrigo Ruiz Aug 29 '16 at 00:52

3 Answers3

8

This will scroll to bottom without any glitch, but if you use Tableview scroll-to-row property then there will be glitch.

For Swift 3 use

self.TableView.reloadData() // To populate your tableview first
//Since we have to wait until the table is reload
 DispatchQueue.main.async {
 let bottomOffset = CGPoint(x: 0, y: self.TableView.contentSize.height - self.TableView.frame.size.height)
 self.TableView.setContentOffset(bottomOffset, animated: false)
 }

For Objective C use

[YourTableView reloadData]; // To populate your tableview first

[YourTableView setContentOffset:CGPointMake(0, YourTableView.contentSize.height - YourTableView.frame.size.height)];
guru
  • 2,727
  • 3
  • 27
  • 39
Irfan Anwar
  • 1,878
  • 17
  • 30
  • maybe for swift : -- : [YourTableView setContentOffset:CGPointMake(0, YourTableView.contentSize.height - YourTableView.frame.size.height) animated:NO]; – Irfan Anwar Aug 29 '16 at 05:41
  • 1
    the above code is not scrolls exact at bottom, it is near 150 px up from the bottom.did you have any idea? – guru Oct 08 '18 at 15:32
  • 1
    @guru : it will scroll exactly to bottom, what u need to check is that your data is loaded completely before `self.TableView.setContentOffset()` function. Follow this link for help: https://stackoverflow.com/questions/16071503/how-to-tell-when-uitableview-has-completed-reloaddata – Irfan Anwar Oct 10 '18 at 08:52
  • Welcome @guru :) also plz Vote Up if u think answer is right so it can also help other developers. Thanks – Irfan Anwar Oct 10 '18 at 11:20
1

EDIT:

animated: false

func scrollBottom() {
    let lastIndex = NSIndexPath(forRow: dataArray.count-1, inSection: 0)
    self.tableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
}

TEST CODE:

import UIKit

class TableViewController: UITableViewController {

var goButton = UIButton()

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.delegate = self
    tableView.dataSource = self

    goButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
    goButton.backgroundColor = UIColor.blueColor()
    goButton.addTarget(self, action: #selector(TableViewController.scrollBottom), forControlEvents: .TouchUpInside)
    self.view.addSubview(goButton)
}



override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return 500
}


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell

    cell.textLabel?.text = "Hello, World!"

    return cell
}

func scrollBottom() {
    let lastIndex = NSIndexPath(forRow: 499, inSection: 0)
    self.tableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
}

}
aatalyk
  • 391
  • 4
  • 15
0

You can either set the content offset:

tableview.contentOffset = CGPoint(x: ??, y: ??)

Or scroll to the desired row

tableview.contentOffset.scrollToItem(at: IndexPath(row: tableview.contentOffset.numberOfItems(inSection: 0) - 1, section: 0), at: .bottom, animated: false)

To get this to happen before the view appears so that the user doesn't see the transition, simply call these methods in the viewDidLayoutSubviews() lifecycle method of your view controller.

CoolPineapple
  • 275
  • 1
  • 3
  • 11