替换后退按钮,但保持滑动以向后导航
Posted
技术标签:
【中文标题】替换后退按钮,但保持滑动以向后导航【英文标题】:Replace back button but keeping swipe to navigate back 【发布时间】:2016-07-04 07:41:29 【问题描述】:首先,我注意到有一个similar question。但是,我想问一下 Swift 中的解决方案。这是我的代码:
override func viewDidLoad()
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Button", style: .Plain, target: self, action: nil)
我想替换后退按钮,但保持滑动以供用户向后导航。但是,这会禁用滑动。我无法在上面的链接中获得接受的答案和建议的答案。这是我试图翻译成 Swift 的内容。
let appearanceNavigationBar = UINavigationBar.appearance()
appearanceNavigationBar.backIndicatorImage = UIImage(named: "back")
appearanceNavigationBar.backIndicatorTransitionMaskImage = UIImage(named: "back")
appearanceNavigationBar.tintColor = UIColor.whiteColor()
我正在使用 Xcode 8.0 beta、Swift 2.3 并在 ios 10.0 中进行测试。任何帮助将不胜感激。
【问题讨论】:
也许你可以看看这个属性:interactivePopGestureRecognizer
@Siam Setting interactivePopGestureRecognizer.enabled = true
什么都不做。重新分配interactivePopGestureRecognizer.delegate
会导致很多问题。 (来自建议的答案)
【参考方案1】:
我用过这个,效果很好:
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
【讨论】:
这行得通。您介意解释一下背后的原因吗? 我还是不知道为什么。我刚刚提到了这个luugiathuy.com/2013/11/…【参考方案2】:接受的答案不完整。如果您配置了故事板转场,并且您在第一个视图控制器上尝试“向后滑动”手势,您可能无法触发转场。
考虑所有边缘情况的最佳解决方案是:
class QFNavigationController:UINavigationController, UIGestureRecognizerDelegate, UINavigationControllerDelegate
override func viewDidLoad()
super.viewDidLoad()
interactivePopGestureRecognizer?.delegate = self
delegate = self
override func pushViewController(_ viewController: UIViewController, animated: Bool)
super.pushViewController(viewController, animated: animated)
interactivePopGestureRecognizer?.isEnabled = false
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool)
interactivePopGestureRecognizer?.isEnabled = true
// IMPORTANT: without this if you attempt swipe on
// first view controller you may be unable to push the next one
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
return viewControllers.count > 1
现在只需在需要时使用QFNavigationController
。
【讨论】:
【参考方案3】:如this answer 中所述将委托设置为nil
会导致iOS 11 中出现一些讨厌的错误,例如this one
但是一般来说,存根委托的想法是好的。比如可以写如下代码
final class NavigationController: UINavigationController
private var customDelegate: InteractivePopGestureRecognizerDelegate?
override func viewDidLoad()
super.viewDidLoad()
customDelegate = InteractivePopGestureRecognizerDelegate(
originalDelegate: interactivePopGestureRecognizer?.delegate,
navigationController: self
)
interactivePopGestureRecognizer?.delegate = customDelegate
然后您可以使用自定义委托来解决问题的根本原因
final class InteractivePopGestureRecognizerDelegate:
NSObject,
UIGestureRecognizerDelegate
private weak var originalDelegate: UIGestureRecognizerDelegate?
private weak var navigationController: UINavigationController?
init(
originalDelegate: UIGestureRecognizerDelegate?,
navigationController: UINavigationController)
self.originalDelegate = originalDelegate
self.navigationController = navigationController
func gestureRecognizer(
_ gestureRecognizer: UIGestureRecognizer,
shouldReceive touch: UITouch)
-> Bool
if let originalDelegate = originalDelegate,
let result = originalDelegate.gestureRecognizer?(
gestureRecognizer,
shouldReceive: touch)
if !result
// Your interactive pop gesture got cancelled here
// Perform sanity check of pop possibility
if (navigationController?.viewControllers.count ?? 0) < 2
return result
if navigationController?.navigationBar.isHidden == true
// Return true here if you want to swipe even without navigation bar
return result
// Enable pop gesture
return true
else
return true
...
// Proxy all other `UIGestureRecognizerDelegate` methods to the originalDelegate here
...
当然,这有点棘手,将来可能无法使用(就像其他所有黑客一样)
【讨论】:
【参考方案4】:好的,所以 3 年过去了,您可能不再需要解决此问题的方法了:) 但也许这会帮助其他人解决此问题。这实际上非常简单:您只需要配置后退按钮,它将从第一个视图控制器显示在第二个视图控制器上。这是一个例子:
class FirstViewController: UIViewController
override func viewDidLoad()
let backButton = UIBarButtonItem(image: UIImage(systemName: "chevron.left.circle.fill"), style: .done, target: nil, action: nil)
navigationItem.backBarButtonItem = backButton
func presentSecondViewController()
navigationController?.pushViewController(SecondViewController(), animated: true)
以这种方式配置 FirstViewController 将允许您在 SecondViewController 上显示自定义后退按钮并保持向后滑动手势。
【讨论】:
以上是关于替换后退按钮,但保持滑动以向后导航的主要内容,如果未能解决你的问题,请参考以下文章
ios15在隐藏导航栏时向后半滑动会留下顶部空白空间 - SwiftUI
在 Swift 3.0 中实现滑动以在没有导航栏的情况下向后导航