Iva*_*ino 4 ios uipresentationcontroller swift3 uipresentingcontroller
我有一个CustomPresentationController用自定义动画进出的动画;
这个特定的控制器被呈现,在屏幕尺寸的 50% 处更少,当我呈现它时,我添加了一个阴影灰色视图,presentingViewController所以它增加了一些深度。
presentedViewController如果我点击我调用默认方法的cancel按钮,我只能关闭。NavBardismiss(:)
我想要完成的是检测 外面的水龙头presentedViewController,也许在灰色区域内,这样我就可以解除presentedViewController,就像解除 ,ActionSheet但我没能做到。让我解释一下我到目前为止所做的尝试。
我试图UITapGestureRecognizer在阴影灰色视图中添加一个,但由于我展示了一个不同的控制器,应用引擎可能认为由于阴影视图不在顶层视图中,它可能无法访问,因此它“阻塞”识别器 - 每当我点击它时,手势手柄都不会触发。
我现在正在实施另外一个向下滑动以关闭,我可以很容易地做到这一点,但我真的希望tap-outside功能也能工作。
关于如何解决这个问题的任何提示?
应用程序图像如下:
小智 6
我的解决方案:
在呈现视图控制器(又名 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)
Run Code Online (Sandbox Code Playgroud)
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
}
}
Run Code Online (Sandbox Code Playgroud)
然后,实现呈现控制器(又名 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)
}
}
Run Code Online (Sandbox Code Playgroud)
我只需在我的一个应用程序中实现这一点。
\n\n我通过添加一个覆盖整个视图的按钮来使其工作,一旦点击该按钮,就会触发 VC 被关闭。
\n\n添加按钮后,您可以在顶部添加自定义视图。
\n\n到目前为止,它看起来运行得很好。
\n\n我的代码如下(我以编程方式完成所有操作,没有故事板)
\n\n //\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\n // MARK: View Life Cycle\n //\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\n\noverride func viewDidLoad() {\n super.viewDidLoad()\n view.backgroundColor = UIColor.clear //VC view background transparent\n setupUI()\n}\n\noverride func viewWillAppear(_ animated: Bool) {\n super.viewWillAppear(animated)\n\n //Animate blackView opacity to 1 to give some depth\n UIView.animate(withDuration: 0.4, delay: 0.2, options: .curveEaseInOut, animations: {\n self.blackView.alpha = 1 \n })\n}\n\n //\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\n // MARK: Setup UI\n //\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\xe2\x80\x94\n\n let blackView: UIView = {\n let view = UIView()\n view.alpha = 0.0\n view.backgroundColor = UIColor.black.withAlphaComponent(0.6)\n return view\n }()\n //Invisible button which covers the entire view that can be tapped \n lazy var dismissLayerBtn: UIButton = {\n let btn = UIButton()\n btn.addTarget(self, action: #selector(tapToDismiss), for: .touchUpInside)\n return btn\n }()\n\n @objc func tapToDismiss() {\n print("tapToDimiss")\n self.dismiss(animated: true, completion: nil)\n }\n\n let milestonePickerView: MilestonePickerView = {\n let view = MilestonePickerView(frame: .zero)\n return view\n }()\n\n func setupUI() {\n\n view.addSubview(blackView)\n view.addSubview(dismissLayerBtn)\n view.addSubview(milestonePickerView) //Important to add the customView after the button.\n\n 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)\n\n 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)\n\n 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)\n\n//I\'m using a custom extension to setup constraints (anchors) \n } \nRun Code Online (Sandbox Code Playgroud)\n\n如果您使用故事板,请确保将不可见按钮放在自定义视图下。
\n\n我希望这有帮助。
\n