UIContextMenu 和 UITableView 问题
UIContextMenu and UITableView issues
我正在尝试添加您可以在 iMessages 中找到的类似 UIContextMenu。当您长按一条消息时,应显示带有某些选项的上下文菜单。
我使用 tableView(_:contextMenuConfigurationForRowAt:point:) 和其他方法。到目前为止一切顺利。
但我遇到了 2 个我无法解决的问题:
最大的变化是预览。当显示上下文菜单并且您收到一条新消息(这会导致 tableview 重新加载)时,预览将更改其内容。所以突然间出现了与您最初选择的消息不同的消息。但我不明白为什么因为没有调用上下文菜单的 tableview 方法......我怎么能解决这个问题?
Apple Messages 停止添加新消息。但是例如 Viber 仍然能够在有上下文菜单的情况下接收新消息。
我想在 tableView(_:willDisplayContextMenu:animator:)
的帮助下像 Apple 一样处理它......但是还有第二个问题 - 此方法仅适用于 iOS +14.0。 . !所以我无法知道 iOS 14?
之前会有上下文菜单
如有任何帮助,我将不胜感激。谢谢
我以某种方式解决了第一个问题。主要思想是使用快照而不是单元格的视图。这样即使重新加载 tableView,快照也保持不变。
您必须实现这两种方法并在那里提供快照:
tableView(_:previewForHighlightingContextMenuWithConfiguration:)
tableView(_:previewForDismissingContextMenuWithConfiguration:)
在我的代码中它看起来像这样:
func tableView(_: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
guard
let messageId = configuration.identifier as? String,
let indexPath = dataSource.indexPath(for: messageId),
let cell = tableView.cellForRow(at: indexPath) as? YourCustomCell else {
return nil
}
return makeTargetedPreview(cell: cell)
}
func makeTargetedPreview(cell: YourCustomCell) -> UITargetedPreview? {
guard
let previewView = cell.viewYouWantToDisplay,
let snapshot = previewView.snapshotView(afterScreenUpdates: false)
else {
return nil
}
// 1. Prepare how should the view in the preview look like
let parameters = UIPreviewParameters()
parameters.backgroundColor = .clear
parameters.visiblePath = UIBezierPath(roundedRect: previewView.bounds, cornerRadius: previewView.layer.cornerRadius)
// 2. Prepare UIPreviewTarget so we can use snapshot
let previewTarget = UIPreviewTarget(
container: previewView,
center: CGPoint(x: previewView.bounds.midX, y: previewView.bounds.midY)
)
// 3. Return UITargetedPreview with snapshot
// important ! We can't use cell's previewView directly as it's getting changed when data reload happens
return UITargetedPreview(view: snapshot, parameters: parameters, target: previewTarget)
}
注意:previewForDismissing(...)
的实现类似。
我正在尝试添加您可以在 iMessages 中找到的类似 UIContextMenu。当您长按一条消息时,应显示带有某些选项的上下文菜单。 我使用 tableView(_:contextMenuConfigurationForRowAt:point:) 和其他方法。到目前为止一切顺利。
但我遇到了 2 个我无法解决的问题:
最大的变化是预览。当显示上下文菜单并且您收到一条新消息(这会导致 tableview 重新加载)时,预览将更改其内容。所以突然间出现了与您最初选择的消息不同的消息。但我不明白为什么因为没有调用上下文菜单的 tableview 方法......我怎么能解决这个问题? Apple Messages 停止添加新消息。但是例如 Viber 仍然能够在有上下文菜单的情况下接收新消息。
我想在
之前会有上下文菜单tableView(_:willDisplayContextMenu:animator:)
的帮助下像 Apple 一样处理它......但是还有第二个问题 - 此方法仅适用于 iOS +14.0。 . !所以我无法知道 iOS 14?
如有任何帮助,我将不胜感激。谢谢
我以某种方式解决了第一个问题。主要思想是使用快照而不是单元格的视图。这样即使重新加载 tableView,快照也保持不变。
您必须实现这两种方法并在那里提供快照: tableView(_:previewForHighlightingContextMenuWithConfiguration:) tableView(_:previewForDismissingContextMenuWithConfiguration:)
在我的代码中它看起来像这样:
func tableView(_: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
guard
let messageId = configuration.identifier as? String,
let indexPath = dataSource.indexPath(for: messageId),
let cell = tableView.cellForRow(at: indexPath) as? YourCustomCell else {
return nil
}
return makeTargetedPreview(cell: cell)
}
func makeTargetedPreview(cell: YourCustomCell) -> UITargetedPreview? {
guard
let previewView = cell.viewYouWantToDisplay,
let snapshot = previewView.snapshotView(afterScreenUpdates: false)
else {
return nil
}
// 1. Prepare how should the view in the preview look like
let parameters = UIPreviewParameters()
parameters.backgroundColor = .clear
parameters.visiblePath = UIBezierPath(roundedRect: previewView.bounds, cornerRadius: previewView.layer.cornerRadius)
// 2. Prepare UIPreviewTarget so we can use snapshot
let previewTarget = UIPreviewTarget(
container: previewView,
center: CGPoint(x: previewView.bounds.midX, y: previewView.bounds.midY)
)
// 3. Return UITargetedPreview with snapshot
// important ! We can't use cell's previewView directly as it's getting changed when data reload happens
return UITargetedPreview(view: snapshot, parameters: parameters, target: previewTarget)
}
注意:previewForDismissing(...)
的实现类似。