使用任何手势关闭 UIPopoverPresentationController,而不仅仅是点击
Dismiss UIPopoverPresentationController with any gesture, not just tap
所以我有一个显示一些内容的简单 UIPopoverPresentationController。
用户可以通过点击屏幕上的任意位置来关闭它(默认弹出行为)。
我希望在用户在屏幕上进行任何类型的点击或手势时关闭弹出窗口。最好是拖动手势。
知道这是否可行吗?以及如何?
尝试使用touchesBegan:withEvent
方法
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first {
if touch.view == self.view {
self.dismiss()
} else {
return
}
}
}
VC 是弹出窗口中显示的视图。
在 presentViewController:animated:completion: 块
[self presentViewController:vc animated:YES completion:^{
UIView *v1 = vc.view.superview.superview.superview;
for (UIView* vx in v1.subviews) {
Class dimmingViewClass = NSClassFromString(@"UIDimmingView");
if ([vx isKindOfClass:[dimmingViewClass class]])
{
UIPanGestureRecognizer* pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(closePopoverOnSwipe)];
[vx addGestureRecognizer:pan];
}
}
}];
您有一个 UIDimmingView,其中包含将关闭的点击手势。只需添加即可。我正在使用 Class dimmingViewClass = NSClassFromString(@"UIDimmingView");
来避免直接使用未记录的 API。我还没有尝试将此 hack 发送给苹果,但下周会尝试。我希望它会过去。但我对此进行了测试,它确实调用了我的选择器。
我使用自定义视图解决了这个问题:
typealias Handler = (() -> Void)?
final class InteractionView: UIView {
var dismissHandler: Handler = nil
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return self
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.dismissHandler?()
}
}
在 viewDidAppear 中配置这个视图并添加到 popover containerView:
fileprivate func configureInteractionView() {
let interactionView = InteractionView(frame: self.view.bounds)
self.popoverPresentationController?.containerView?.addSubview(interactionView)
interactionView.backgroundColor = .clear
interactionView.isUserInteractionEnabled = true
interactionView.dismissHandler = { [weak self] in
self?.hide()
}
}
fileprivate func hide() {
self.dismiss(animated: true, completion: nil)
}
我对这个问题的解决方案。
例如,如果您创建一个名为 MyPopoverViewController 的 class UIViewController 来呈现 PopViewController。
然后在 viewDidLoad() 或 viewWillAppear(_ animated:) 方法中添加两个 GestureRecognizer 如下:
protocal MyPopoverControllerDelegate {
func shouldDismissPopover()
}
class MyPopoverViewController : UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// back trace to root view, if it is a UIWindows, add PanGestureRecognizer
// and LongPressGestureRecognizer, to dismiss this PopoverViewController
for c in sequence(first: self.view, next: { [=10=].superview}) {
if let w = c as? UIWindow {
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(dismissPopover(gesture:)))
w.addGestureRecognizer(panGestureRecognizer)
let longTapGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(dismissPopover(gesture:)))
w.addGestureRecognizer(longTapGestureRecognizer)
}
}
@objc private func dismissPopover(gesture: UIGestureRecognizer) {
delegate?.shouldDismissPopover()
}
}
然后在这个 PopOverViewController 呈现的主要 ViewController 中实现协议方法。
extension YourMainViewController: MyPopoverControllerDelegate {
func shouldDismissPopover() {
self.presentedViewController?.dismiss(animated: true, completion: nil)
}
}
所以我有一个显示一些内容的简单 UIPopoverPresentationController。
用户可以通过点击屏幕上的任意位置来关闭它(默认弹出行为)。
我希望在用户在屏幕上进行任何类型的点击或手势时关闭弹出窗口。最好是拖动手势。
知道这是否可行吗?以及如何?
尝试使用touchesBegan:withEvent
方法
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first {
if touch.view == self.view {
self.dismiss()
} else {
return
}
}
}
VC 是弹出窗口中显示的视图。 在 presentViewController:animated:completion: 块
[self presentViewController:vc animated:YES completion:^{
UIView *v1 = vc.view.superview.superview.superview;
for (UIView* vx in v1.subviews) {
Class dimmingViewClass = NSClassFromString(@"UIDimmingView");
if ([vx isKindOfClass:[dimmingViewClass class]])
{
UIPanGestureRecognizer* pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(closePopoverOnSwipe)];
[vx addGestureRecognizer:pan];
}
}
}];
您有一个 UIDimmingView,其中包含将关闭的点击手势。只需添加即可。我正在使用 Class dimmingViewClass = NSClassFromString(@"UIDimmingView");
来避免直接使用未记录的 API。我还没有尝试将此 hack 发送给苹果,但下周会尝试。我希望它会过去。但我对此进行了测试,它确实调用了我的选择器。
我使用自定义视图解决了这个问题:
typealias Handler = (() -> Void)?
final class InteractionView: UIView {
var dismissHandler: Handler = nil
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return self
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.dismissHandler?()
}
}
在 viewDidAppear 中配置这个视图并添加到 popover containerView:
fileprivate func configureInteractionView() {
let interactionView = InteractionView(frame: self.view.bounds)
self.popoverPresentationController?.containerView?.addSubview(interactionView)
interactionView.backgroundColor = .clear
interactionView.isUserInteractionEnabled = true
interactionView.dismissHandler = { [weak self] in
self?.hide()
}
}
fileprivate func hide() {
self.dismiss(animated: true, completion: nil)
}
我对这个问题的解决方案。 例如,如果您创建一个名为 MyPopoverViewController 的 class UIViewController 来呈现 PopViewController。 然后在 viewDidLoad() 或 viewWillAppear(_ animated:) 方法中添加两个 GestureRecognizer 如下:
protocal MyPopoverControllerDelegate {
func shouldDismissPopover()
}
class MyPopoverViewController : UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// back trace to root view, if it is a UIWindows, add PanGestureRecognizer
// and LongPressGestureRecognizer, to dismiss this PopoverViewController
for c in sequence(first: self.view, next: { [=10=].superview}) {
if let w = c as? UIWindow {
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(dismissPopover(gesture:)))
w.addGestureRecognizer(panGestureRecognizer)
let longTapGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(dismissPopover(gesture:)))
w.addGestureRecognizer(longTapGestureRecognizer)
}
}
@objc private func dismissPopover(gesture: UIGestureRecognizer) {
delegate?.shouldDismissPopover()
}
}
然后在这个 PopOverViewController 呈现的主要 ViewController 中实现协议方法。
extension YourMainViewController: MyPopoverControllerDelegate {
func shouldDismissPopover() {
self.presentedViewController?.dismiss(animated: true, completion: nil)
}
}