调用reloadRowsAtIndexPaths方法时动态单元格高度导致弹跳效果

时间:2015-02-18 02:19:01

标签: ios uitableview core-data

背景:在tableView中,每个单元格都包含一个显示为图像的按钮。我想要显示的效果是,当我点击图像(实际上是按钮)时,按钮的图像会变为另一个图像。
错误:假设有很多数据(超过一页),如果我点击一个单元格的按钮,按钮的图像会改变,但副作用是整个表格查看首先向上滚动一点(如弹跳效果),然后向下滚动到前一个位置 我做了什么

    ViewDidLoad方法中的
  1. inboxListTableView.estimatedRowHeight = 60 inboxListTableView.rowHeight = UITableViewAutomaticDimension
  2. 当我点击按钮时(true和false表示不同的图像和tableView(cellForRowAtIndex :)方法中的定义):

    let cell = sender.superview?.superview as InboxListCellTableViewCell
        if let indexPath = inboxListTableView.indexPathForCell(cell) {
            let actionToUpdate = actions[indexPath.row]
            actionToUpdate.imageButton = !actionToUpdate.imageButton.boolValue
            var e: NSError?
            if !MOContext.save(&e) {
                println(e?.description)
            }
        }
    
  3. 然后在获取结果控制器委托方法中:

    func controllerWillChangeContent(controller: NSFetchedResultsController) {
        inboxListTableView.beginUpdates()
    }
    
    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath!, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath!) {
        switch type {
        case .Insert:
            inboxListTableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
        case .Delete:
            inboxListTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        case .Update:
            inboxListTableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
        default:
            inboxListTableView.reloadData()
        }
        actions = controller.fetchedObjects as [Action]
    }
    
    func controllerDidChangeContent(controller: NSFetchedResultsController) {
        inboxListTableView.endUpdates()
    }
    
  4. 我认为这个bug可能由两个方面引起:CoreData和Self sizing cell(动态单元格高度)。因为当我使用数组来保存动作([Action])而不是CoreData时,我没有遇到错误。但是,当我对此代码发表评论inboxListTableView.rowHeight = UITableViewAutomaticDimension时,它没有反弹/向上滚动"但是牢房的高度是固定的。

    有什么想法吗?什么都可以帮忙!谢谢:))

2 个答案:

答案 0 :(得分:1)

我遇到了完全相同的问题:使用动态细胞高度时会有一点反弹。我的情况不同,我没有使用NSFetchedResultsController,我也改变了单元格的高度(展开和折叠它们)。

经过大量的实验,我找到了一个简单的解决方案。只需在reloadRowsAtIndexPaths之后调用scrollToRowAtIndexPath。它对我有用。

tableView.reloadRows(at: [indexPath], with: .none)
tableView.scrollToRow(at: indexPath, at: .none, animated: true)

当我展开和折叠单元格时,我调用此代码。 我希望你能在项目中使用它。

答案 1 :(得分:0)

我认为问题的实用解决方案是使用NSFetchedResultsControllerDelegate方法进行此特定更新。

您可以直接在按钮处理程序中更改按钮的图像。您必须在获取结果控制器委托的.Update情况下检查此情况,并确保调用reloadRowsAtIndexPaths方法。

现在您正在避免自动UI更新机制,并且不应该发生此问题。

顺便说一句,依靠表视图单元的视图层次结构访问索引路径(superview.superview...)是非常糟糕的做法。几年前,Apple改变了细胞的工作方式,依赖类似范例的代码也破裂了。与集合视图单元格相同。

相反,做这样的事情:

func buttonHandler(sender: UIButton) {
    let point = sender.convertPoint(CGPointZero, toView:self.tableView)
    let indexPath = self.tableView.indexPathForRowAtPoint(point)
}