繁体   English   中英

iOS - 关闭在其视图之外触摸的呈现视图控制器

[英]iOS - Dismiss presented view controller touching outside its View

我有一个CustomPresentationController ,它使用自定义动画进出动画;

这个特定的控制器被呈现,在屏幕尺寸的 50% 处更少,当我呈现它时,我向presentingViewController添加了一个阴影灰色视图,因此它增加了一些深度。

如果我点击NavBarcancel按钮,我只能关闭presentedViewController ,我调用默认的dismiss(:)方法。

我想要完成的是检测presentedViewController之外的点击,可能在灰色区域内,这样我就可以关闭presentedViewController ,就像关闭ActionSheet但我没有做到。 让我解释一下我到目前为止所做的尝试。

我试图将一个UITapGestureRecognizer添加到阴影灰色视图中,但由于我展示了一个不同的控制器,应用引擎可能认为由于阴影视图不在顶层视图中,所以它可能无法访问,因此它“阻塞” ' 识别器 - 每当我点击它时,手势句柄都不会触发。

我现在正在实施另外一个向下滑动以关闭,我可以很容易地做到这一点,但我真的希望tap-outside功能也能正常工作。

关于如何解决这个问题的任何提示?

应用程序图像如下:

截图

我的解决方案:

在呈现视图控制器(又名 ViewControllerA)时:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
                
let vcb = storyboard.instantiateViewController(withIdentifier: "ViewControllerB") as! ViewControllerB // ViewControllerB is the presented view controller 
        
vcb.modalPresentationStyle = .custom
        
vcb.transitioningDelegate = self

modalRatio = Float(0.5) // modalRatio is an object property 
   
self.present(pvc, animated: true)

ViewControllerA 还应实现转换委托:

extension ViewControllerA: UIViewControllerTransitioningDelegate {
        
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
                
        return PartialSizePresentController(presentedViewController: presented, presenting: presenting, withRatio: modalRatio ?? 0.5) // modal ratio is configurable using modalRatio property
        
    }
    
}

然后,实现呈现控制器(又名 PartialSizePresentController),以便它也处理点击手势:

class PartialSizePresentController: UIPresentationController {
    
    let heightRatio : CGFloat
    
    init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?, withRatio ratio: Float = 0.5) {
        
        heightRatio = CGFloat(ratio)
        
        super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
        
    }

    override var frameOfPresentedViewInContainerView: CGRect {
        
        guard let cv = containerView else { fatalError("No container view available") }
        
        return CGRect(x: 0, y: cv.bounds.height * (1 - heightRatio), width: cv.bounds.width, height: cv.bounds.height * heightRatio)
        
    }
    
    override func presentationTransitionWillBegin() {
        
        let bdView = UIView(frame: containerView!.bounds)
        
        bdView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        
        containerView?.addSubview(bdView)
        
        bdView.addSubview(presentedView!)
        
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(PartialSizePresentController.handleTap(_:)))
        
        bdView.addGestureRecognizer(tapGesture)
        
    }
    
    @objc func handleTap(_ sender: UITapGestureRecognizer) {
        presentedViewController.dismiss(animated: true, completion: nil)
    }
}

尝试使用我的以下代码:

您需要在您作为弹出窗口使用的控制器中实现此方法。

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
   // Here write down you logic to dismiss controller     
}

希望这会奏效。 :D

我只需要在我的一个应用程序中实现它。

我通过添加一个覆盖整个视图的按钮来实现它,这个按钮一旦被点击就会触发 VC 被关闭。

添加按钮后,您可以在顶部添加自定义视图。

到目前为止,它看起来运行良好。

我的代码如下(我以编程方式执行所有操作,没有故事板)

    //—————————————————————————————
    // MARK: View Life Cycle
    //—————————————————————————————

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.clear //VC view background transparent
    setupUI()
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    //Animate blackView opacity to 1 to give some depth
    UIView.animate(withDuration: 0.4, delay: 0.2, options: .curveEaseInOut, animations: {
        self.blackView.alpha = 1 
    })
}

    //————————————————
    // MARK: Setup UI
    //————————————————

    let blackView: UIView = {
        let view = UIView()
        view.alpha = 0.0
        view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
        return view
    }()
    //Invisible button which covers the entire view that can be tapped 
    lazy var dismissLayerBtn: UIButton = {
        let btn = UIButton()
        btn.addTarget(self, action: #selector(tapToDismiss), for: .touchUpInside)
        return btn
    }()

    @objc func tapToDismiss() {
        print("tapToDimiss")
        self.dismiss(animated: true, completion: nil)
    }

    let milestonePickerView: MilestonePickerView = {
        let view = MilestonePickerView(frame: .zero)
        return view
    }()

    func setupUI() {

        view.addSubview(blackView)
        view.addSubview(dismissLayerBtn)
        view.addSubview(milestonePickerView) //Important to add the customView after the button.

        blackView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)

        dismissLayerBtn.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)

        milestonePickerView.anchor(top: nil, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 20, paddingBottom: 40, paddingRight: 20, width: 0, height: 400)

//I'm using a custom extension to setup constraints (anchors) 
   } 

如果您使用故事板,请确保将不可见按钮放在自定义视图下。

我希望这会有所帮助。

// 这个对我有用

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    var touch: UITouch? = touches.first
    if touch?.view == yourView {
        navigationController?.popViewController(animated: true)
        dismiss(animated: true, completion: nil)
    }
}

您使用UITapGestureRecognizer在正确的轨道上。 只要确保你实现shouldRecognizeSimultaneouslyWith如下:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

这应该允许手势正确触发。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM