替换后退按钮但保持滑动以返回
Replace back button but keeping swipe to navigate back
首先,我注意到有一个similar question。但是,我想问一下 Swift 中的解决方案。这是我的代码:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Button", style: .Plain, target: self, action: nil)
}
我想替换后退按钮,但要保留滑动以供用户返回导航。但是,这会禁用滑动。我无法获得上面 link 中接受的答案和建议的答案。这是我试图翻译成 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 中进行测试。任何帮助将不胜感激。
我用过这个并且有效:
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
按照 causes some nasty bugs in iOS 11, for example this one
中所述将委托设置为 nil
但总的来说,对委托进行存根的想法是好的。比如你可以写下面的代码
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
...
}
当然这有点棘手,将来可能行不通(就像其他黑客一样)
好的,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 上显示自定义后退按钮并保持向后滑动手势。
接受的答案不完整。如果您配置了情节提要转场并尝试在第一个视图控制器上使用 "swipe back" 手势,您可能无法触发转场。
将所有边缘情况都考虑在内的最佳解决方案是:
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
。
首先,我注意到有一个similar question。但是,我想问一下 Swift 中的解决方案。这是我的代码:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Button", style: .Plain, target: self, action: nil)
}
我想替换后退按钮,但要保留滑动以供用户返回导航。但是,这会禁用滑动。我无法获得上面 link 中接受的答案和建议的答案。这是我试图翻译成 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 中进行测试。任何帮助将不胜感激。
我用过这个并且有效:
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
按照
nil
但总的来说,对委托进行存根的想法是好的。比如你可以写下面的代码
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
...
}
当然这有点棘手,将来可能行不通(就像其他黑客一样)
好的,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 上显示自定义后退按钮并保持向后滑动手势。
接受的答案不完整。如果您配置了情节提要转场并尝试在第一个视图控制器上使用 "swipe back" 手势,您可能无法触发转场。
将所有边缘情况都考虑在内的最佳解决方案是:
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
。