Son Nguyen
Son Nguyen

Reputation: 1634

iOS: Keep UITableView at the same position when reloadData

I'm running into an annoying problem. I'm doing a messaging app. In the message page, when the user scrolls to the top, as soon as the topmost cell becomes visible, it will load more messages to display. Because at the time of loading more messages, the position of the table view is at the top (content offset is 0), after done loading messages, I call reloadData and iOS tries to maintain the offset which consequentially scrolls to the top of the table view again and triggers another load. This is like an infinite loop until there is no more message to load. I tried to call scrollToRow right after reloadData but no luck.

So anything that can keep the table view at the same position (i.e. if before loading, message "a" is at the top, after loading, message "a" still at the top of the screen) after calling reloadData will work for me.

Spent several hours on this so I'll really appreciate any help. Thanks

Upvotes: 3

Views: 3290

Answers (4)

Alessandro Ornano
Alessandro Ornano

Reputation: 35392

With modern swift you can make it in "one line only" with ternary:

(tableView.indexPathsForVisibleRows)?.isEmpty ?? true ? tableView.reloadData() : tableView.reloadRows(at: tableView.indexPathsForVisibleRows!, with: .none)

Upvotes: 1

Sam Vyatkin
Sam Vyatkin

Reputation: 236

Don't call reloadData every time when you need to insert just one row; it's bad practice.

UITableView has the method:

func insertRows(at indexPaths: [IndexPath], 
           with animation: UITableViewRowAnimation)

...and since iOS 11, also:

func performBatchUpdates(_ updates: (() -> Void)?, 
              completion: ((Bool) -> Void)? = nil)

...which allow you to perform multiple insert, delete, reload, and move operations as a group.

Upvotes: 2

Nikhil Manapure
Nikhil Manapure

Reputation: 3878

I don't know if this help you but you can try this while reloading-

if let indexPaths = tableView.indexPathsForVisibleRows {
    tableView.reloadRows(at: indexPaths, with: .none)
} else {
    tableView.reloadData()
}

Upvotes: 4

Manish Mahajan
Manish Mahajan

Reputation: 2082

First update your modelArray and then call reloadData() method of TableView.

It seems you have to implement pagination. Use this method for api call, it will call api once reached at last cell.

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    //Bottom Refresh
    if scrollView == yourTableView {
        if ((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height) {
            if !isNewDataLoading {
                isNewDataLoading = true
                apiCall()
            }
        }
    }
}

Make sure you set isNewDataLoading to false once API has responded successfully.

Upvotes: -1

Related Questions