5

iOS 13.4(2020 年 3 月)更新:

UIPointerInteraction将鼠标悬停在链接上时也会发生这种情况。


当用户长按链接时,我有一个显示富文本并显示 iOS 13 上下文菜单的视图。当用户开始长按时,我希望能够仅突出显示链接而不是整个视图。

为此,我提供了一个UITargetedPreview对象,其中包含要在视图中突出显示的每行UIPreviewParameters的s。这正确地突出了链接,但也有隐藏视图其余部分的不良副作用CGRectUIContextMenuInteractionDelegate

这张图说明了这个问题:

在此处输入图像描述

请注意,当链接正确突出显示时,视图的其余部分会随着链接的长按然后释放而闪烁。

将此与 Apple 自己的 Notes.app 中的行为进行比较:

在此处输入图像描述

请注意,当长按链接时,视图的其余部分不会消失。这在 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)
}

UITargetedPreview我在and的文档中找不到任何内容UIPreviewParameters,所以有人知道如何做到这一点吗?

4

2 回答 2

4

好的,感谢WebKit中的实现,我终于找到了如何做到这一点。我做错的是没有提供有针对性的预览 a 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)

于 2020-04-03T08:36:53.263 回答
0

您的解决方案非常有用。我使用 hitTest 来检测 highligted 视图,我对结果感到高兴,所以只想分享。

- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction previewForHighlightingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration {    
    UIView *view = interaction.view;
    CGPoint location = [interaction locationInView:view];
    // Detecting the hittable subview at the given location
    UIView *subView = [view hitTest:location withEvent:nil];
    if (subView) {
        CGRect highlightedRect = subView.frame;
        UIPreviewParameters *previewParameters = [UIPreviewParameters new];
        previewParameters.backgroundColor = subView.backgroundColor;
        previewParameters.visiblePath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, highlightedRect.size.width, highlightedRect.size.height)];

        return [[UITargetedPreview alloc] initWithView:subView parameters:previewParameters];
    }
    return nil;
}

于 2020-11-04T12:57:43.763 回答