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?
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.
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)
})
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)
}
tableView.reloadData()
if tableView.numberOfRowsInSection(0) > 0
{
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self. tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
}
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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With