【问题标题】:How to reload programmatically moved row?如何以编程方式重新加载移动的行?
【发布时间】:2013-08-06 15:13:26
【问题描述】:

令人沮丧的事实:在调用tableView:moveRowAtIndexPath:toIndexPath: 之后,tableView:cellForRowAtIndexPath: 没有被调用该行。

UITableView 更新块内的tableView:moveRowAtIndexPath:toIndexPath: 之后或之前调用reloadRowsAtIndexPaths:withRowAnimation: 也不起作用:它会引发不一致错误

我看到了 2 个解决方法:删除+插入,而不是在另一个更新块中移动或重新加载。

我的问题是:是否有其他方法可以在同一更新块内重新加载和移动 UITableView 的行?

【问题讨论】:

  • 用于索引目的:Inconsistency error: attempt to perform an insert and a move to the same index path。我也遇到了这个问题,并且在您的两种解决方法之间进行了权衡,即动画对用户来说有多清晰。为什么这还没有解决,不知道。感谢您的提问。

标签: ios uitableview


【解决方案1】:

我认为不可能同时进行移动和重新加载。我尝试了几种方法,我想出的最佳解决方案是在批量更新之前进行重新加载。我没有为reloadRows 制作动画,因为它似乎与批量更新动画冲突。

[tableView reloadRowsAtIndexPaths:indexPathsToReload withRowAnimation:UITableViewRowAnimationNone];
[tableView beginUpdates];
//inserts, deletes and moves here
[tableView endUpdates];

另外,我通常将我的单元配置逻辑放在一个单独的方法中,例如:

- (void)tableView:(UITableView *)tableView configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;

这样我就可以直接调用它并完全绕过reloadRowsAtIndexPaths。您也不会通过这种方式获得内置动画,但您可以制作自己的动画。

【讨论】:

  • 这似乎是最好的方法。奇怪的是,在更新块中调用 reloadData 会取消动画。
  • 只有在 endUpdates 调用之后发生重新加载调用时,我才能让它工作。
  • 如果我们只是“删除”和“插入”而不是“移动”,则该行是“移动”和“重新加载”。
【解决方案2】:

我在对“dateModified”进行排序时遇到了类似的问题,但我也在单元格的标签上显示了该属性。 “移动”和“更新”都是必需的。仅调用了“移动”,因此正确的单元格被带到了列表的顶部,但标签文本没有更新。

我的简单 UITableViewCell 解决方案。

首先,您像往常一样拨打 .move 电话。在您调用自定义配置方法后直接 - 该方法负责为单元格上的“更新”设置动画。

 func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
    case .insert:
        tableView.insertRows(at: [newIndexPath!], with: .fade)
    case .delete:
        tableView.deleteRows(at: [indexPath!], with: .fade)
    case .update:
        tableView.reloadRows(at: [indexPath!], with: .fade)
    case .move:
        tableView.moveRow(at: indexPath!, to: newIndexPath!)

        // Can't "reload" and "move" to same cell simultaneously.

        // This is an issue because I'm sorting on date modified and also displaying it within a
        // label in the UITableViewCell.

        // To have it look perfect you have to manually crossfade the label text, while the UITableView
        // does the "move" animation.

        let cell = tableView.cellForRow(at: indexPath!)!
        let note = fetchedResultsController.object(at: newIndexPath!)
        configure(cell: cell, note: note, animated: true)
    }
}

configure 方法如下所示(注意动画是可选的):

internal func configure(cell: UITableViewCell, note: Note, animated: Bool = false) {
    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .medium
    dateFormatter.timeStyle = .medium
    let dateString = dateFormatter.string(from: note.dateModified as Date)

    if animated {
        UIView.transition(with: cell.contentView, duration: 0.3, options: .transitionCrossDissolve, animations: {
            cell.textLabel?.text = dateString
        }, completion: nil)
    } else {
        cell.textLabel?.text = dateString
    }
}

这里重用configure方法,不带动画:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseIdentifier, for: indexPath)
    let note = fetchedResultsController.object(at: indexPath)

    configure(cell: cell, note: note)

    return cell
}

如果你有一个更复杂的单元格(子类),你可以将 configure 方法移到子类代码中。重要的部分是有一个方法来更新单元格数据,动画可选。

【讨论】:

  • “不能同时“重新加载”和“移动”到同一个单元格。”对此见解 +1
【解决方案3】:
[_tableview beginUpdates];

// write code here to delete and move row...

[_tableview endUpdates];

 // now after end update call reload method to reload cell..  

    [self.tableview reloadRowsAtIndexPaths:[NSArray arrayWithObjects:
    [NSIndexPath indexPathForRow:_arrayForData.count-1 inSection:indexpathforSelectedRow.section], nil] withRowAnimation:UITableViewRowAnimationNone];

【讨论】:

  • 我对此问题的经验是,@Timothy-moose 建议的解决方案仅在更新后发生重新加载时才有效,而不是在此解决方案建议的更新之前。
【解决方案4】:

我在 [TableView reloadData] 方面取得了成功。确保您正在更新数据源,并将重新加载代码放置在适当的位置。

【讨论】:

  • reloadData 无关。实际上,我的主要目标是摆脱 reloadData,因为它很难看(例如闪烁)并且会打扰用户。
猜你喜欢
  • 1970-01-01
  • 2012-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-10
  • 2012-03-08
  • 1970-01-01
相关资源
最近更新 更多