如何使用 UIPreviewParameters 将文本范围指定为 UUIContextMenuInteraction 的突出显示预览而不隐藏视图的其余部分?
How to use UIPreviewParameters to specify a range of text as a highlighted preview for UIContextMenuInteraction without hiding the rest of the view?
iOS13.4(2020 年 3 月)更新:
将鼠标悬停在 link 上时,UIPointerInteraction
也会发生这种情况。
当用户长按 link 时,我有一个显示富文本并显示 iOS 13 上下文菜单的视图。当用户开始长按时,我希望能够仅突出显示 link 而不是整个视图。
为此,我提供了一个 UITargetedPreview
对象,其中包含 UIPreviewParameters
,每行的 CGRect
将突出显示到视图的 UIContextMenuInteractionDelegate
。这正确地突出显示了 link、,但也隐藏了视图的其余部分。
这张图片演示了问题:
请注意,虽然 link 正确突出显示,但随着 link 长按然后松开,视图的其余部分会闪烁。
将此与 Apple 自己的行为进行比较 Notes.app:
请注意,当长按 link 时,视图的其余部分不会消失。这在 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
的文档中找不到任何内容,所以有人知道如何做到这一点吗?
好的,多亏了 an implementation in WebKit,我终于找到了解决办法。我做错的是没有提供目标预览 UIPreviewTarget
.
要仅突出显示视图的一部分,您需要:
提供 UIPreviewParameters 说明要在预览中显示的视图部分,并将背景颜色设置为与要预览的视图相同
提供一个 UIPreviewTarget 建立:
- 整个视图作为动画的容器
- 显示部分的中心作为动画的中心
Create a snapshot of the portion of the view you want to show and designate it as view of the 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)
您的解决方案非常有用。我使用 hitTest 来检测高亮视图,我对结果很满意,所以只想分享。
- (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;
}
iOS13.4(2020 年 3 月)更新:
将鼠标悬停在 link 上时,UIPointerInteraction
也会发生这种情况。
当用户长按 link 时,我有一个显示富文本并显示 iOS 13 上下文菜单的视图。当用户开始长按时,我希望能够仅突出显示 link 而不是整个视图。
为此,我提供了一个 UITargetedPreview
对象,其中包含 UIPreviewParameters
,每行的 CGRect
将突出显示到视图的 UIContextMenuInteractionDelegate
。这正确地突出显示了 link、,但也隐藏了视图的其余部分。
这张图片演示了问题:
请注意,虽然 link 正确突出显示,但随着 link 长按然后松开,视图的其余部分会闪烁。
将此与 Apple 自己的行为进行比较 Notes.app:
请注意,当长按 link 时,视图的其余部分不会消失。这在 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
的文档中找不到任何内容,所以有人知道如何做到这一点吗?
好的,多亏了 an implementation in WebKit,我终于找到了解决办法。我做错的是没有提供目标预览 UIPreviewTarget
.
要仅突出显示视图的一部分,您需要:
提供 UIPreviewParameters 说明要在预览中显示的视图部分,并将背景颜色设置为与要预览的视图相同
提供一个 UIPreviewTarget 建立:
- 整个视图作为动画的容器
- 显示部分的中心作为动画的中心
Create a snapshot of the portion of the view you want to show and designate it as view of the 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)
您的解决方案非常有用。我使用 hitTest 来检测高亮视图,我对结果很满意,所以只想分享。
- (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;
}