Проблемы UIContextMenu и UITableView

Я пытаюсь добавить аналогичное UIContextMenu, которое вы можете найти в iMessages. При долгом нажатии на сообщение должно отображаться контекстное меню с некоторыми параметрами. Я использую tableView(_:contextMenuConfigurationForRowAt:point:) и другие методы. Все идет нормально.

Но у меня возникли 2 проблемы, которые я не могу решить:

  1. самый большой из них - изменение превью. Когда отображается контекстное меню и вы получаете новое сообщение (которое вызывает перезагрузку tableview), предварительный просмотр изменит свое содержимое. Итак, неожиданно появляется сообщение, отличное от того, которое вы выбрали изначально. Но я не понимаю, почему, потому что методы tableview для контекстного меню не вызываются ... как я могу это решить? Apple Messages перестает добавлять новое сообщение. Но, например, Viber все еще может получать новое сообщение, пока есть контекстное меню.

  2. Я хотел как-то разобраться с этим, как Apple, с помощью tableView(_:willDisplayContextMenu:animator:)... но есть вторая проблема - этот метод только для iOS +14.0 ..! Итак, как я могу узнать, что до iOS 14 будет контекстное меню?

Буду признателен за любую помощь. Спасибо.

1 ответ

Решение

Как-то мне удалось решить первую проблему. Основная идея - использовать снимки вместо просмотра ячейки. Таким образом, даже если tableView перезагружается, снимок остается прежним.

Вы должны реализовать эти 2 метода и предоставить снимок там: 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(...) похож.

Другие вопросы по тегам