Error: UITableView jump to top with UITableViewAut

2019-01-17 16:46发布

I am using UITableView with estimatedRowHeight and UITableViewAutomaticDimension. Also I am using NSFetchedResultsControllerDelegate to reflect the changes.

Everything is work fine. Now the problem is when ever I add some record to CoreData, NSFetchedResultsController called the it's delegate but an unexpected things happen. TableView suddenly scroll to Top every time.

NSFetchedResultsControllerDelegate

func controllerWillChangeContent(controller: NSFetchedResultsController) {
    tableView.beginUpdates()
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    tableView.endUpdates()
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        switch type {
        case .Insert:
            tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .None)
            break

        case .Update:
            tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .None)
            break

        case .Delete:
            tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .None)
            break

        default: break;
        }
    }

By googling I found few answers where people suggested to use tableView: heightForRowAtIndexPath: but as my cell height is dynamic. So what should I do?

7条回答
干净又极端
2楼-- · 2019-01-17 17:04

Adding to @jayesh-miruliya 's answer, in your NSFetchedResultsControllerDelegate after the switch statement, put this in your code:

tableView.reloadData()
dispatch_async(dispatch_get_main_queue(), {
    let topCellIndexPath = NSIndexPath(forRow: 0, inSection: 0)
    self. tableView.scrollToRowAtIndexPath(topCellIndexPath, atScrollPosition: .Top, animated: true)
})
查看更多
倾城 Initia
3楼-- · 2019-01-17 17:04
  func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    switch type {
    case .Insert:

      tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .None)
        break

    case .Update:
        tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .None)
        break

    case .Delete:
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .None)
        break

    default: break;
    }
   tableView.reloadData()
  let indexPath = NSIndexPath(forRow: 0, inSection: 0)
  self. tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
   }

}
查看更多
Summer. ? 凉城
4楼-- · 2019-01-17 17:05

This is default behaviour of tableview, inserting an row in tableview scroll it to top. I did faced the same issue with my app. Here is how i able to manage the content offset of tableview, follow the steps,

1)Store the content offset of UITableview before inserting row or section.

2)Insert objects in array.

3)Reload the tableview

4)Subtract the difference and set the content offset manually.

let oldOffset: CGFloat = tblTest.contentSize.height
tblTest.reloadData()
let newOffset: CGFloat = tblTest.contentSize.height
tblTest.setContentOffset(CGPointMake(0, (newOffset - oldOffset)), animated: false)

This is how i have done in my applications so far, and with dynamic cell to overcome the reinitialise cell everytime, it is working just awesome.

查看更多
来,给爷笑一个
5楼-- · 2019-01-17 17:10

To solve my problem I save the cell height in the willDisplay method and in estimatedHeightForRowAt I'm retrieving the value.

var cellHeights = NSMutableDictionary()

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    if let height = cellHeights.object(forKey: indexPath) {
        return height as! CGFloat
    }

    return UITableViewAutomaticDimension
}

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    cellHeights.setObject(cell.frame.size.height, forKey: indexPath as NSCopying)
}
查看更多
男人必须洒脱
6楼-- · 2019-01-17 17:12
let cou : Int = self.Array.count as Int
let lastindex : NSIndexPath = NSIndexPath(forRow: cou-1, inSection: 0)
self.TableName.scrollToRowAtIndexPath(lastindex, atScrollPosition: UITableViewScrollPosition.None, animated: true)

This code help you to scroll your tableview at particular position.

查看更多
Evening l夕情丶
7楼-- · 2019-01-17 17:16
tableView.reloadData()
if tableView.numberOfRowsInSection(0) > 0
{
      let indexPath = NSIndexPath(forRow: 0, inSection: 0)
      self. tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
}
查看更多
登录 后发表回答