You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在WKWebView Popover显示时保持SCNView响应并仅通过铃铛按钮关闭?

解决方案

1. 让SCNView在Popover显示时保持响应

默认情况下,UIPopoverPresentationController会拦截背后视图的所有交互,我们只需要通过passthroughViews属性,把你的scnView加入到允许穿透交互的视图列表里,就能让SCNView的相机控制手势正常工作了。

修改你的onBellBtnPressed方法,添加这一行代码:

myWebViewVC.popoverPresentationController?.passthroughViews = [scnView]

2. 仅允许点击铃铛按钮关闭Popover

默认的Popover行为是点击外部区域自动关闭,要改这个逻辑,我们需要实现UIPopoverPresentationControllerDelegate的相关方法,同时自己管理Popover的显示状态:

第一步:添加状态跟踪变量

在MainVC里新增一个属性,用来记录Popover是否处于显示状态:

var isPopoverPresented = false

第二步:修改铃铛按钮的点击逻辑

点击按钮时,如果Popover已经显示就关闭它,否则弹出它:

@IBAction func onBellBtnPressed(_ sender: UIButton) {
    if isPopoverPresented {
        // 关闭Popover并更新状态
        dismiss(animated: true) {
            self.isPopoverPresented = false
        }
        return
    }
    
    // 弹出Popover的逻辑
    myWebViewVC.modalPresentationStyle = .popover
    myWebViewVC.popoverPresentationController?.delegate = self
    myWebViewVC.popoverPresentationController?.sourceView = sender
    myWebViewVC.popoverPresentationController?.sourceRect = sender.bounds
    // 允许SCNView穿透交互
    myWebViewVC.popoverPresentationController?.passthroughViews = [scnView]
    
    present(myWebViewVC, animated: true) {
        self.isPopoverPresented = true
    }
}

第三步:实现代理方法阻止默认关闭行为

添加两个代理方法,一个阻止外部点击关闭,另一个确保状态变量在Popover意外关闭时同步更新:

// 阻止点击外部区域关闭Popover
func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
    return false
}

// Popover被关闭时更新状态变量
func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
    isPopoverPresented = false
}

完整修改后的MainVC代码

class MainVC: UIViewController, UIPopoverPresentationControllerDelegate { 
    @IBOutlet weak var scnView: SCNView! 
    @IBOutlet weak var bellBtn: UIButton! 
    var myWebViewVC: MyWebViewVC!
    var isPopoverPresented = false // 跟踪Popover显示状态

    override func viewDidLoad() { 
        super.viewDidLoad() 
        let scene = SCNScene(named: "art.scnassets/DemoScene.scn")! 
        scnView.scene = scene 
        scnView.allowsCameraControl = true 
    } 

    @IBAction func onBellBtnPressed(_ sender: UIButton) {
        if isPopoverPresented {
            dismiss(animated: true) {
                self.isPopoverPresented = false
            }
            return
        }
        
        myWebViewVC.modalPresentationStyle = .popover
        myWebViewVC.popoverPresentationController?.delegate = self
        myWebViewVC.popoverPresentationController?.sourceView = sender
        myWebViewVC.popoverPresentationController?.sourceRect = sender.bounds
        myWebViewVC.popoverPresentationController?.passthroughViews = [scnView]
        
        present(myWebViewVC, animated: true) {
            self.isPopoverPresented = true
        }
    }

    func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
        return false
    }

    func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
        isPopoverPresented = false
    }
}

这样修改后,就能完全满足你的需求:

  • Popover显示期间,SCNView的相机控制手势可以正常响应
  • 只有点击铃铛按钮才能关闭Popover,点击外部区域不会触发关闭

内容的提问来源于stack exchange,提问作者grzebyk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:26:20