我必须确保用户知道,在执行弹出操作之前,他将失去编辑视图控制器中的修改。为此,我创建了一个闭包,它将返回true/false,对应于是否应该继续弹出或应该阻止弹出的决定。
是当滑动与弹出的手势我遇到一个意想不到的行为:viewWillDisappear被调用,但控制器并没有消失。viewDidDisappear永远不会被调用。此外,屏幕是冻结的,但我可以按下标签栏项目跳转到另一个控制器。当返回到当前选项卡项时,视图控制器已经弹出,但最终,我将遇到其他冻结。
你能想到解决这个问题的办法吗?谢谢!
//自定义导航控制器代码
var popHandler: (() -> Bool)?
override func popViewController(animated: Bool) -> UIViewController?
{
guard self.popHandler?() != false else
{
return nil
}
self.popHandler = nil
return super.popViewController(animated: animated)
}
//编辑控制器的代码
func setupPopHandler() {
guard let navigationController = self.navigationController as? MyCustomNavController else {
return
}
navigationController.popHandler = { [weak self] in
guard let self = self else { return true }
if self.hasChangedFields() && self.hasUnsavedWork == true {
let alert = UIAlertController(title: "Info", message: "You have unsaved changes", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Save", style: .default, handler: { action in
// Call save method which will pop the VC after saving
}))
alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler: { action in
self.hasUnsavedWork = false
self.navigationController?.popViewController(animated: true)
}))
self.present(alert, animated: true)
return false
} else {
return true
}
}
}
找到一个可行的解决方案。如果你在interactivePopGestureRecognizer
触发popViewController
时取消它,它将真正扰乱显示队列。如果设置了popHandler
,则使用自定义UIScreenEdgeGestureRecognizer。
/// Custom UINavigationController that can block a dismiss via a set `popHandler`
/// - Important: `interactivePopGestureRecognizer` will be set to `true` when a viewController is dismissed.
open class BlockerNavigationController: UINavigationController, UIGestureRecognizerDelegate {
private var gesture: UIScreenEdgePanGestureRecognizer?
/// Return `true` if dismissal is allowed
open var popHandler: (() -> Bool)? {
didSet {
if popHandler != nil {
interactivePopGestureRecognizer?.isEnabled = false
gesture?.isEnabled = true
} else {
interactivePopGestureRecognizer?.isEnabled = true
gesture?.isEnabled = false
}
}
}
/// handle edge swipe cases
@objc private func onEdgeSwipe(gesture: UIPanGestureRecognizer) {
// handle dismissals via edge swipes
if gesture.state == .began {
if popHandler?() == false
{
return
}
self.popHandler = nil
if viewControllers.count > 1 {
viewControllers.last?.dismiss(animated: true)
} else {
dismiss(animated: true, completion: nil)
}
}
}
open override func popViewController(animated: Bool) -> UIViewController?
{
// handle dismissals via `dismiss`
guard self.popHandler?() != false else
{
return nil
}
self.popHandler = nil
return super.popViewController(animated: animated)
}
open override func viewDidLoad() {
super.viewDidLoad()
gesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(onEdgeSwipe(gesture:)))
gesture?.delegate = self
gesture?.edges = .left
gesture?.isEnabled = false
view.addGestureRecognizer(gesture!)
}
}