Как использовать UIPreviewParameters, чтобы указать диапазон текста в качестве выделенного предварительного просмотра для UIContextMenuInteraction, не скрывая остальную часть представления? - PullRequest
3 голосов
/ 26 января 2020

Обновление для iOS 13,4 (март 2020 г.):

Это также происходит с UIPointerInteraction при наведении на ссылки.


I есть представление, которое отображает форматированный текст и показывает контекстное меню iOS 13, когда пользователь долго нажимает на ссылку. Я хочу иметь возможность выделить только ссылку, а не весь вид, когда пользователь начинает долго нажимать.

Для этого я предоставляю объект UITargetedPreview, который содержит UIPreviewParameters с CGRect s. каждой строки, которая будет выделена до UIContextMenuInteractionDelegate представления. Это правильно выделяет ссылку, , но имеет нежелательный побочный эффект, который также скрывает остальную часть вида .

Это изображение демонстрирует проблему:

enter image description here

Обратите внимание, что, хотя ссылка выделена правильно, остальная часть представления мигает, когда ссылка долго нажимается, а затем освобождается.

Сравните это с поведением в собственных заметках Apple.app:

enter image description here

Обратите внимание, что остальная часть представления не исчезает при длительном нажатии на ссылку. Это также работает, как и ожидалось, в других приложениях Apple (например, Safari).


Я предоставляю UITargetedPreview s делегату взаимодействия следующим образом:

func contextMenuInteraction(_ interaction: UIContextMenuInteraction, previewForHighlightingMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
    guard let range = configuration.identifier as? NSRange else { return nil }        
    let lineRects: [NSValue] = // calculate appropriate rects for the range of text
    let parameters = UIPreviewParameters(textLineRects: lineRects)
    return UITargetedPreview(view: /* the rich text view */, parameters: parameters)
}

func contextMenuInteraction(_ interaction: UIContextMenuInteraction, previewForDismissingMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
    guard let range = configuration.identifier as? NSRange else { return nil }        
    let lineRects: [NSValue] = // calculate appropriate rects for the range of text
    let parameters = UIPreviewParameters(textLineRects: lineRects)
    return UITargetedPreview(view: /* the rich text view */, parameters: parameters)
}

I ничего не могу найти в какой документации есть для UITargetedPreview и UIPreviewParameters, так кто-нибудь знает, как это можно сделать?

1 Ответ

0 голосов
/ 03 апреля 2020

ОК, я наконец-то узнал, как это сделать, благодаря реализации в WebKit . То, что я делал неправильно, не предоставляло целевой предварительный просмотр UIPreviewTarget.

. Чтобы выделить только часть представления, вам необходимо:

  1. Предоставить параметры UIPreviewParameters с указанием часть вида, отображаемая в предварительном просмотре, и установите цвет фона, совпадающий с видом, который вы хотите предварительно просмотреть

  2. Предоставьте UIPreviewTarget , который устанавливает:

    • весь вид в качестве контейнера анимации
    • центр отображаемой части в качестве центра анимации
  3. Создайте снимок части представления, которую вы хотите показать, и обозначьте его как представление UITargetedPreview .

В коде этого выглядит так:

let view: UIView = // the view with the context menu interaction
let highlightedRect: CGRect = // the rect of the highlighted portion to show

// 1        
let previewParameters = UIPreviewParameters()
previewParameters.visiblePath = // path of highlighted portion of view to show, remember you can use UIPreviewParameters.init(textLineRects:) for text
previewParameters.backgroundColor = view.backgroundColor

// 2: Notice that we're passing the whole view in here
let previewTarget = UIPreviewTarget(container: view, center: CGPoint(x: highlightedRect.midX, y: highlightedRect.midY))

// 3: Notice that we're passing the snapshot view in here - not the whole view
let snapshot = view.resizableSnapshotView(from: highlightedRect, afterScreenUpdates: true, withCapInsets: .zero)!
return UITargetedPreview(view: snapshot, parameters: previewParameters, target: previewTarget)

...