How to reload tableview after reordering a row? Rows have variable height

2.6k views Asked by At

I let user to reorder rows in tableView. Because this event affects content - some numeric values in cells should be updated - in all the other rows, I call a reloadData in moveRowAtIndexPath. And then strange effects occur.

I.e. cells seems overlapping when touching dragger, and some cell starts to move up and down. Its important to know, that cells height are varying.

The strange, that if I remove reloadData from moveRowAtIndexPath, then all these phenomenons disappear. Only the content is invalid.

So how should I reload data after reordering?


UPDATE: What I have done meantime reconfiguring cells in viewDidLayoutSubviews instead of call reloadData end of the moveRowAtIndexPath. And it works 90% like I expect, but still rows are sometimes somewhat higher they should.

override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {

    //..

    reorderOccured = true
}

override func viewDidLayoutSubviews() {

    if reorderOccured {

        for cell in tableView.visibleCells() as! [UITableViewCell] {

            let ip = tableView.indexPathForCell(cell)
            if ip != nil {
                self.configureCell(cell, indexPath: ip!)
            }
        }

        reorderOccured = false
    }
}
3

There are 3 answers

1
János On BEST ANSWER

I found here the answer: https://stackoverflow.com/a/4692563/239219

[tableView beginUpdates];
[tableView endUpdates];

This code forces UITableView to reload cell sizes only, but not cell contents.

5
pteofil On

You shouldn't call reloadData after reorder. You have to make the same changes to your data, as the changes that has been made on the screen. For example: if you moved cell nr 2 to position 6, you have to remove your object that populate cell nr.2 and insert it again at position 6. You didn't provide enough details, but usually you would keep your data in an array of objects. This array you have to make the changes to, so your backing datasource is valid.

Here's a link to details from Apple.

I just read the updated after I posted my answer. It seems like you really need to reloadData. In this case I advise to reload after a small delay with a dispatch_async block on the main thread. Say after 0.1.

0
the_dude_abides On

I can't yet comment on pteofil's answer, but he is correct: if you have a numbered set of rows in a table, and you move one calling moveRow(...), your animation for the move will be cancelled by a tableView.reloadData().

As such I delayed the data reload (which renumbers all the visible cells based on the updated data source (don't forget to do that when you move stuff around!)) a couple hundred milliseconds and it works perfectly now and looks great too.