UITableView破坏性上下文菜单动画

问题描述

我正在将iOS13上下文菜单添加到我的表视图中。菜单操作之一允许用户删除该项目:

override func tableView(_ tableView: UITableView,contextMenuConfigurationForRowAt indexPath: IndexPath,point: CGPoint) -> uicontextmenuconfiguration? {
    return uicontextmenuconfiguration(identifier: nil,previewProvider: nil) { suggestedActions in
       let deleteAction = UIAction(title: "Delete",image: UIImage(systemName: "trash.fill"),identifier: nil,discoverabilityTitle: "",attributes: UIMenuElement.Attributes.destructive) { action in
            self.data.remove(at: indexPath.row)

            //Remove from the table.
            self.tableView.deleteRows(at: [indexPath],with: .automatic)
        }

        return UIMenu(title: "",children: [deleteAction])
    }
}

我正在使用认的预览视图控制器(因此它只显示单元格)。我目前看到的是一个奇怪的动画工件,其中显示了上下文菜单预览,而要删除的行下方的项目则以动画形式显示,然后预览逐渐淡出为白色(因此列表中似乎有空白行),然后表格将重新绘制并显示被掩盖的项目。

enter image description here

这使用的是认单元格,但是当使用具有更多信息的自定义单元格时,情况看起来更糟。无论如何,有没有可以使这个动作更好的动画?

解决方法

我也遇到了这个问题。该错误可能是由于删除,移动或更改了用于生成预览的原始单元所致。

我发现的解决方案是实现委托方法tableView(_:previewForHighlightingContextMenuWithConfiguration:),将原始单元格作为视图传递给委托方法,但是自定义UIPreviewParameters以使用UIColor.clear

    override func tableView(_ tableView: UITableView,previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
        guard let indexPath = configuration.identifier as? IndexPath,let cell = tableView.cellForRow(at: indexPath) else {
            return nil
        }
        
        let parameters = UIPreviewParameters()
        parameters.backgroundColor = .clear
        
        return UITargetedPreview(view: cell,parameters: parameters)
    }

为了在此委托方法中标识原始单元格,您需要一种方法来对其进行标识。一种方法是将indexPath设置为UIContextMenuConfiguration的标识符,例如:

    override func tableView(_ tableView: UITableView,contextMenuConfigurationForRowAt indexPath: IndexPath,point: CGPoint) -> UIContextMenuConfiguration? {
        return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath,previewProvider: nil) { _ in
            return UIMenu(title: "",children: [
                UIAction(title: "Delete",image: UIImage(systemName: "trash"),attributes: .destructive) { action in
                    self.data.remove(at: indexPath.row)
                    tableView.deleteRows(at: [indexPath],with: .automatic)
                }
            ])
        }
    }

但是,如果您的数据可以在上下文菜单的显示和操作之间改变,那么您需要一种更可靠的方法来对其进行识别。

我不必实现tableView(_:previewForDismissingContextMenuWithConfiguration:)即可起作用。