Mikhail Sein
Mikhail Sein

Reputation: 329

iOS TableView reload and scroll top

the second day I can not solve the problem with the table.

We have a segmentedControl which, when changed, changes the table. Suppose that there are 3 elements in the segment of the control and, correspondingly, 3 arrays (which is important, they are of different sizes) I need to scroll table up when segmentedControl is changed.

And it seems like everything is simple: contentOffset = .zero and reloadData ()

But. This does not work, I do not know why the table not scroll up.

The only thing that worked:

UIView.animate (withDuration: 0.1, animations: {
            self.tableView.contentOffset = .zero
        }) {(_) in
            self.tableView.reloadData ()
}

But now there is another problem when the table goes up, a bug may occur, because the segmentedControl has changed, and the data in the other array may not be, we have not yet done reloadData ()

Maybe I can not understand the obvious things)) Congrats on the upcoming holidays!

Upvotes: 19

Views: 29974

Answers (7)

JaspreetKour
JaspreetKour

Reputation: 837

Swift 5.1*, tried one line code and worked for me:

tableView?.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

Added this code to my tableview to align the content to start from top.

Hope will be helping. :)

Upvotes: 0

black_pearl
black_pearl

Reputation: 2719

Perfectly to the top of page on reload, by twice reloading

No disturbing animation

dataForSource = nil
tableView.reloadData()

DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
    self.dataForSource = realData
    self.tableView.reloadData()
}

Upvotes: 1

Prashant Tukadiya
Prashant Tukadiya

Reputation: 16466

Okay. So people finding issue with scrolling a tableview to the top with

self.tableView.setContentOffset(.zero, animated: false)

And need to do reload data unnecessarily to fix this !

So What is the issue with setContentOffset is kind of bug of iOS ?
The smallest and simplest answer is NO so what's the issue then ?

The answer is that dynamic row is using UITableView.automaticDimension. Tableview calculates its content offset with row height and with the number or sections and rows you have in your data source. So in case of dynamic height is not performing the scrollToTop correctly, it is because it needs to recalculate every row height and content size.

So to reduce this bundle from tableview we, can provide an estimated row height like

self.tableView.estimatedRowHeight = 117 // whatever your value 

Hopefully this will help someone :)

Upvotes: 4

AshvinGudaliya
AshvinGudaliya

Reputation: 3324

UItableView method scrollToRow(at:at:animated:) Scrolls through the table view until a row identified by index path is at a particular location on the screen.

Use

tableView.scroll(to: .top, animated: true)

You can use my extension

extension UITableView {

    public func reloadData(_ completion: @escaping ()->()) {
        UIView.animate(withDuration: 0, animations: {
            self.reloadData()
        }, completion:{ _ in
            completion()
        })
    }

    func scroll(to: scrollsTo, animated: Bool) {
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
            let numberOfSections = self.numberOfSections
            let numberOfRows = self.numberOfRows(inSection: numberOfSections-1)
            switch to{
            case .top:
                if numberOfRows > 0 {
                     let indexPath = IndexPath(row: 0, section: 0)
                     self.scrollToRow(at: indexPath, at: .top, animated: animated)
                }
                break
            case .bottom:
                if numberOfRows > 0 {
                    let indexPath = IndexPath(row: numberOfRows-1, section: (numberOfSections-1))
                    self.scrollToRow(at: indexPath, at: .bottom, animated: animated)
                }
                break
            }
        }
    }

    enum scrollsTo {
        case top,bottom
    }
}

Upvotes: 35

rbaldwin
rbaldwin

Reputation: 4888

I was getting the following error after trying to scroll to top straight after calling a reloadData

[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (0) beyond bounds (0) for section (0).'

This fixed it for me:

    tableView.reloadData()
    if tableView.numberOfRows(inSection: 0) != 0 {
        tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
    }

Upvotes: 10

Pandurang Yachwad
Pandurang Yachwad

Reputation: 1723

I found better way to do this. It works like a charm.

let topIndex = IndexPath(row: 0, section: 0)
tableView.scrollToRow(at: topIndex, at: .top, animated: true)

Upvotes: 6

Baltej Singh
Baltej Singh

Reputation: 39

you can use this.

    tableView.setContentOffset(CGPoint.zero, animated: true)

you can set animated as your requirement

Upvotes: 0

Related Questions