20

I am facing problem in my app - you can post and edit your favorite places. After posting a post, or editing a specific post (UITableViewCell), UITableview is reloaded.

My problem is: the UITableview scrolls to the top after reloading. But that's not what I want. I want my view to stay on the cell / view where I was. But I don't know how to manage that.

Could you help me?

Sohil R. Memon
  • 8,982
  • 1
  • 28
  • 56
debbiedowner
  • 338
  • 1
  • 3
  • 10
  • 1
    Have you looked at the UITableView method: reloadRowsAtIndexPaths – Dominic Jun 03 '16 at 12:58
  • have a look at this answer http://stackoverflow.com/questions/28043632/auto-scrolling-to-a-cell-with-a-specific-value you might need to save the index you are looking at when you reload to know where to scroll to – Tyler Pierog Jun 03 '16 at 13:03

5 Answers5

24

Igor's answer is correct if you are using dynamically resizable cells (UITableViewAutomaticDimension)

Here it is in swift 3:

    private var cellHeights: [IndexPath: CGFloat?] = [:]
    var expandedIndexPaths: [IndexPath] = []

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cellHeights[indexPath] = cell.frame.height
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if let height = cellHeights[indexPath] {
            return height ?? UITableViewAutomaticDimension
        }
        return UITableViewAutomaticDimension
    }


    func expandCell(cell: UITableViewCell) {
      if let indexPath = tableView.indexPath(for: cell) {
        if !expandedIndexPaths.contains(indexPath) {
            expandedIndexPaths.append(indexPath)
            cellHeights[indexPath] = nil
            tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
            //tableView.scrollToRow(at: indexPath, at: .top, animated: true)
        }
      }
    }
Kurt J
  • 2,327
  • 19
  • 17
  • surprisingly this helped and I am not using dynamic cell heights. Thank you! – Paul Lehn Mar 14 '18 at 13:56
  • 1
    yeah this code is useful when you adding a dynamic row height using programatically. I was calculating row height from textview text. Small bump comes in when reloading tableview. Adding this code will remove that small bump. – prateek sharma Feb 19 '19 at 05:14
  • Whats the purpose of expandCell() method, I couldn't understand it. Is it just for demonstration or i need to use it as well in my code? – Asad Ali Choudhry Nov 01 '20 at 13:35
16

To prevent scrolling to top, you should save heights of cells when they loads and give exact value in tableView:estimatedHeightForRowAtIndexPath:

// declare cellHeightsDictionary
NSMutableDictionary *cellHeightsDictionary;

// initialize it in ViewDidLoad or other place
cellHeightsDictionary = @{}.mutableCopy;

// save height
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    [cellHeightsDictionary setObject:@(cell.frame.size.height) forKey:indexPath];
}

// give exact height value
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber *height = [cellHeightsDictionary objectForKey:indexPath];
    if (height) return height.doubleValue;
    return UITableViewAutomaticDimension;
}
Igor
  • 11,227
  • 4
  • 49
  • 69
  • this works, but can you explain why heightForRowAt is not enough? – DeyaEldeen Oct 12 '18 at 16:53
  • 1
    This is working for the tableviews when doing for bottom scroll. But not working in case of top scroll. Can you give some suggestion what may be the issue exactly? – Gautam Shrivastav Dec 29 '19 at 18:23
  • Do you mean a case when you scroll to some indexPath programmatically, skipping some first rows? If yes, then you can do pre-calculate heights. – Igor Dec 29 '19 at 22:03
  • Facing same issue as @Gautam Shrivastav, When scroll to top and load new rows at top, it auto scrolls to top of new data, rather it should keep on the last visible cell. – Asad Ali Choudhry Nov 01 '20 at 13:57
11

The UITableView's reloadData() method is explicitly a force reload of the entire tableView. It works well, but is usually jarring and a bad user experience if you're going to do that with a tableview that the user is currently looking at.

Instead, take a look at reloadRowsAtIndexPaths(_:withRowAnimation:) and reloadSections(_:withRowAnimation:) in the documentation.

SpacyRicochet
  • 2,214
  • 2
  • 22
  • 39
6

Just go for these lines if you want an easy solution

let contentOffset = tableView.contentOffset
tableView.reloadData()
tableView.setContentOffset(contentOffset, animated: false)
pkamb
  • 26,648
  • 20
  • 124
  • 157
zeiteisen
  • 6,877
  • 5
  • 44
  • 68
-1

In swift 3.1

DispatchQueue.main.async(execute: {

    self.TableView.reloadData()
    self.TableView.contentOffset = .zero

})
Mahipalsinh
  • 125
  • 7