如何在WKWebView中禁用iOS 11和iOS 12拖放?

问题描述 投票:1回答:3

在iOS 11和12上的WKWebView中长按图像或链接会启动拖放会话(用户可以拖动图像或链接)。我怎么能禁用它?

ios drag-and-drop ios11 wkwebview
3个回答
2
投票

我确实找到了一个solution that involves method swizzling,但它也可以在没有任何调配的情况下禁用WKWebView中的拖放。

注意:请参阅下面的iOS 12.2+特别说明

WKContentView - WKWebViewWKScrollView的私人子视图 - 有一个interactions属性,就像iOS 11+中的任何其他UIView一样。那interactions属性包含UIDragInteractionUIDropInteraction。简单地将enabled设置为false上的UIDragInteraction就可以了。

我们不希望访问任何私有API并使代码尽可能稳固。

假设你的WKWebView被称为webView

if (@available(iOS 11.0, *)) {        
    // Step 1: Find the WKScrollView - it's a subclass of UIScrollView
    UIView *webScrollView = nil;

    for (UIView *subview in webView.subviews) {
        if ([subview isKindOfClass:[UIScrollView class]]) {
            webScrollView = subview;
            break;
        }
    }

    if (webScrollView) {
        // Step 2: Find the WKContentView
        UIView *contentView = nil;

        // We don't want to trigger any private API usage warnings, so instead of checking
        // for the subview's type, we simply look for the one that has two "interactions" (drag and drop)
        for (UIView *subview in webScrollView.subviews) {
            if ([subview.interactions count] > 1) {
                contentView = subview;
                break;
            }
        }

        if (contentView) {
            // Step 3: Find and disable the drag interaction
            for (id<UIInteraction> interaction in contentView.interactions) {
                if ([interaction isKindOfClass:[UIDragInteraction class]]) {
                    ((UIDragInteraction *) interaction).enabled = NO;
                    break;
                }
            }
        }
    }
}

而已!

适用于iOS 12.2+的特别说明

上面的代码仍适用于iOS 12.2,但是调用它时很重要。在iOS 12.1及更低版本中,您可以在创建WKWebView后立即调用此代码。那是不可能的。 WKContentViewinteractions数组在它首次创建时是空的。只有在将WKWebView添加到附加到UIWindow的视图层次结构后才会填充它 - 只需将其添加到尚未成为可见视图层次结构一部分的超级视图是不够的。在视图控制器中,viewDidAppear很可能是一个安全的地方来调用它。

How did I find this out?

这是输出:

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 50.1  
  * frame #0: 0x00000001115b726c WebKit`-[WKContentView(WKInteraction) setupDataInteractionDelegates]  
    frame #1: 0x00000001115a8852 WebKit`-[WKContentView(WKInteraction) setupInteraction] + 1026  
    frame #2: 0x00000001115a5155 WebKit`-[WKContentView didMoveToWindow] + 79 

很明显,UIDragInteraction的创建和添加是由移动到(被添加到)窗口的视图触发的。


1
投票

基于Johannes FahrenKrug的Post,有一些变化。

private func disableDragAndDropInteraction() {
    var webScrollView: UIView? = nil
    var contentView: UIView? = nil

    if #available(iOS 11.0, *) {
        if (webView != nil) {
            for subView in webView!.subviews {
                if (subView is UIScrollView) {
                    webScrollView = subView
                    break
                }
            }

            if (webScrollView != nil) {
                for subView in webScrollView!.subviews {
                    if subView.interactions.count > 1 {
                        contentView = subView
                        break
                    }
                }

                if (contentView != nil) {
                    for interaction in contentView!.interactions {
                        if interaction is UIDragInteraction {
                            contentView!.removeInteraction(interaction)
                        }
                    }
                }
            }
        } else {
            // Fallback on earlier versions
        }
    }
}

1
投票

这很棒!感谢@basha的快速版本。

我做了同样的事情但是使用了一些compactMaps来减少if语句和守卫的深度以摆脱力量展开。

private func disableDragAndDropInteraction() {
    var webScrollView: UIView? = nil
    var contentView: UIView? = nil

    if #available(iOS 11.0, *) {
        guard let noDragWebView = webView else { return }
        webScrollView = noDragWebView.subviews.compactMap { $0 as? UIScrollView }.first
        contentView = webScrollView?.subviews.first(where: { $0.interactions.count > 1 })
        guard let dragInteraction = (contentView?.interactions.compactMap { $0 as? UIDragInteraction }.first) else { return }
        contentView?.removeInteraction(dragInteraction)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.