在 UINavigationController 中隐藏导航栏时不向后滑动
Posted
技术标签:
【中文标题】在 UINavigationController 中隐藏导航栏时不向后滑动【英文标题】:No Swipe Back when hiding Navigation Bar in UINavigationController 【发布时间】:2014-09-02 19:38:44 【问题描述】:我喜欢将您的视图嵌入到UINavigationController
中继承的滑动包。不幸的是,我似乎找不到隐藏NavigationBar
的方法,但仍然让触摸屏向后滑动gesture
。我可以编写自定义手势,但我不喜欢而是依赖UINavigationController
向后滑动gesture
。
如果我在情节提要中取消选中它,则向后滑动不起作用
或者,如果我以编程方式隐藏它,同样的场景。
- (void)viewDidLoad
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES animated:NO]; // and animated:YES
有没有办法隐藏顶部NavigationBar
仍然可以滑动?
【问题讨论】:
添加 UIGestureRecognizer 是否可以接受?实施起来轻而易举。 @LancelotdelaMare,我试图避免这种情况,因为它不会像 UINavigationController 向后滑动一样顺畅。我正在研究 UIScreenEdgePanGestureRecognizer,因为有些人说它有帮助但还没有让它工作。在这里寻找最简单、最优雅的解决方案。 【参考方案1】:一个可行的技巧是将interactivePopGestureRecognizer
的UINavigationController
代表设置为nil
,如下所示:
[self.navigationController.interactivePopGestureRecognizer setDelegate:nil];
但在某些情况下,它可能会产生奇怪的效果。
【讨论】:
"当堆栈上只有一个视图控制器时,反复向后滑动可能会导致手势被识别,这反过来又会使 UI 处于停止识别的(我认为 UIKit 工程师出乎意料的)状态任何手势” 另一种可能防止这种意外状态的方法是将其设置为一些低级对象(我使用了我的应用程序委托)并实现gestureRecognizerShouldBegin
,如果navigationController
返回true
的viewController
计数大于 0。
虽然这可行,但我强烈建议不要这样做。破坏委托会导致罕见且难以识别的主线程块。原来它不是主线程块,而是@HorseT 所描述的。
我的应用程序保存了委托句柄,然后在viewWillDisappear
中恢复它,到目前为止还没有遇到不良副作用。
!!!!强烈建议不要使用此解决方案,当反复使用滑动时出现奇怪的行为,背部被禁用,整个应用不再响应【参考方案2】:
其他方法的问题
设置interactivePopGestureRecognizer.delegate = nil
会产生意想不到的副作用。
设置navigationController?.navigationBar.hidden = true
确实有效,但不允许隐藏导航栏中的更改。
最后,通常更好的做法是为导航控制器创建一个模型对象 UIGestureRecognizerDelegate
。将其设置为 UINavigationController
堆栈中的控制器是导致 EXC_BAD_ACCESS
错误的原因。
完整解决方案
首先,将这个类添加到您的项目中:
class InteractivePopRecognizer: NSObject, UIGestureRecognizerDelegate
var navigationController: UINavigationController
init(controller: UINavigationController)
self.navigationController = controller
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
return navigationController.viewControllers.count > 1
// This is necessary because without it, subviews of your top controller can
// cancel out your gesture recognizer on the edge.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
return true
然后,将导航控制器的 interactivePopGestureRecognizer.delegate
设置为新的 InteractivePopRecognizer
类的实例。
var popRecognizer: InteractivePopRecognizer?
override func viewDidLoad()
super.viewDidLoad()
setInteractiveRecognizer()
private func setInteractiveRecognizer()
guard let controller = navigationController else return
popRecognizer = InteractivePopRecognizer(controller: controller)
controller.interactivePopGestureRecognizer?.delegate = popRecognizer
享受没有副作用的隐藏导航栏,即使您的***控制器有表格、集合或滚动视图子视图,它也能正常工作。
【讨论】:
很好的解决方案! 最佳答案,谢谢! @HunterMaximillionMonk 感谢您提供出色的解决方案。它就像一个魅力 绝对是最佳答案! 适用于 ios 13.5、12.4.6 和 10.3.4。谢谢。【参考方案3】:在我的情况下,为了防止奇怪的影响
根视图控制器
override func viewDidLoad()
super.viewDidLoad()
// Enable swipe back when no navigation bar
navigationController?.interactivePopGestureRecognizer?.delegate = self
// UIGestureRecognizerDelegate
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
if let navVc = navigationController
return navVc.viewControllers.count > 1
return false
【讨论】:
有时我在使用这个时会遇到 EXC_BAD_ACCESS 对我来说,它不会使手势起作用,并且经常与EXEC_BAD_ACCESS
崩溃
记得将UIGestureRecognizerDelegate
添加到根视图控制器...在我的情况下,委托在比根视图控制器更晚的视图控制器中设置为 nil,所以当返回到根视图控制器时, gestureRecognizerShouldBegin
没有被调用。所以我把.delegate = self
放在viewDidAppear()
中。这解决了我的情况下的奇怪影响..干杯!
@AndreyGordeev 您能否详细说明EXEC_BAD_ACCESS
何时发生?
这里有更多关于EXC_BAD_ACCESS
的信息错误:***.com/questions/28746123/…【参考方案4】:
为 iOS 13.4 更新
iOS 13.4 打破了之前的解决方案,所以事情会变得很糟糕。看起来在 iOS 13.4 中,此行为现在由私有方法 _gestureRecognizer:shouldReceiveEvent:
控制(不要与 iOS 13.4 中添加的新公共 shouldReceive
方法混淆)。
我发现其他发布的解决方案覆盖委托或将其设置为 nil 会导致一些意外行为。
在我的情况下,当我在导航堆栈的顶部并尝试使用手势再弹出一个时,它会失败(如预期的那样),但随后尝试压入堆栈会开始导致奇怪的图形导航栏中的故障。这是有道理的,因为委托不仅仅用于处理在导航栏隐藏时是否阻止手势被识别,而且所有其他行为都被丢弃。
从我的测试来看,gestureRecognizer(_:, shouldReceiveTouch:)
似乎是原始委托实施的方法,用于在隐藏导航栏时阻止手势被识别,而不是gestureRecognizerShouldBegin(_:)
。在其委托工作中实现 gestureRecognizerShouldBegin(_:)
的其他解决方案,因为缺少 gestureRecognizer(_:, shouldReceiveTouch:)
的实现将导致接收所有触摸的默认行为。
@Nathan Perry 的解决方案接近了,但如果没有实现 respondsToSelector(_:)
,向委托发送消息的 UIKit 代码将认为没有任何其他委托方法的实现,并且永远不会调用 forwardingTargetForSelector(_:)
.
因此,在我们想要修改行为的一个特定场景中,我们控制 `gestureRecognizer(_:, shouldReceiveTouch:),否则将其他所有内容转发给委托。
class AlwaysPoppableNavigationController : UINavigationController
private var alwaysPoppableDelegate: AlwaysPoppableDelegate!
override func viewDidLoad()
super.viewDidLoad()
self.alwaysPoppableDelegate = AlwaysPoppableDelegate(navigationController: self, originalDelegate: self.interactivePopGestureRecognizer!.delegate!)
self.interactivePopGestureRecognizer!.delegate = self.alwaysPoppableDelegate
private class AlwaysPoppableDelegate : NSObject, UIGestureRecognizerDelegate
weak var navigationController: AlwaysPoppableNavigationController?
weak var originalDelegate: UIGestureRecognizerDelegate?
init(navigationController: AlwaysPoppableNavigationController, originalDelegate: UIGestureRecognizerDelegate)
self.navigationController = navigationController
self.originalDelegate = originalDelegate
// For handling iOS before 13.4
@objc func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
if let navigationController = navigationController, navigationController.isNavigationBarHidden && navigationController.viewControllers.count > 1
return true
else if let originalDelegate = originalDelegate
return originalDelegate.gestureRecognizer!(gestureRecognizer, shouldReceive: touch)
else
return false
// For handling iOS 13.4+
@objc func _gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceiveEvent event: UIEvent) -> Bool
if let navigationController = navigationController, navigationController.isNavigationBarHidden && navigationController.viewControllers.count > 1
return true
else if let originalDelegate = originalDelegate
let selector = #selector(_gestureRecognizer(_:shouldReceiveEvent:))
if originalDelegate.responds(to: selector)
let result = originalDelegate.perform(selector, with: gestureRecognizer, with: event)
return result != nil
return false
override func responds(to aSelector: Selector) -> Bool
if #available(iOS 13.4, *)
// iOS 13.4+ does not need to override responds(to:) behavior, it only uses forwardingTarget
return originalDelegate?.responds(to: aSelector) ?? false
else
if aSelector == #selector(gestureRecognizer(_:shouldReceive:))
return true
else
return originalDelegate?.responds(to: aSelector) ?? false
override func forwardingTarget(for aSelector: Selector) -> Any?
if #available(iOS 13.4, *), aSelector == #selector(_gestureRecognizer(_:shouldReceiveEvent:))
return nil
else
return self.originalDelegate
【讨论】:
看起来您的解决方案是目前最好的。谢谢! “但随后尝试压入堆栈将开始导致导航栏中出现奇怪的图形故障” - 我在这里感到困惑。我以为我们没有导航栏?这就是问题所在?在我的情况下,我嵌入了一个导航控制器作为没有导航栏的子视图控制器;包含的 VC 具有导航控件。所以我让包含的 VC 成为识别器的代表,只是做了gestureRecognizerShouldBegin:
的事情,它“似乎工作”。想知道我应该注意什么。
这有内存泄漏,因为 navigationController
是 AlwaysPoppableDelegate 中的强引用。我已经编辑了代码以使其成为weak
参考。
这个不错的解决方案在 iOS 13.4 中不再适用
@ChrisVasselli 真的很棒,谢谢!希望这将通过 App Store 审查的私有方法检查。【参考方案5】:
你可以继承 UINavigationController 如下:
@interface CustomNavigationController : UINavigationController<UIGestureRecognizerDelegate>
@end
实施:
@implementation CustomNavigationController
- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated
[super setNavigationBarHidden:hidden animated:animated];
self.interactivePopGestureRecognizer.delegate = self;
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
if (self.viewControllers.count > 1)
return YES;
return NO;
@end
【讨论】:
使用这种方法会破坏UIPageViewController
overscroll 中的弹出手势。
我发现 viewController.count > 1 检查是必要的。如果用户尝试仅使用根 VC 向后滑动,则 UI 将在下一次 VC 推送时挂起。【参考方案6】:
简单、无副作用的答案
虽然这里的大多数答案都很好,但它们似乎有意想不到的副作用(应用程序崩溃)或冗长。
我能想到的最简单但最实用的解决方案如下:
在您隐藏导航栏的 ViewController 中,
class MyNoNavBarViewController: UIViewController
// needed for reference when leaving this view controller
var initialInteractivePopGestureRecognizerDelegate: UIGestureRecognizerDelegate?
override func viewDidLoad()
super.viewDidLoad()
// we will need a reference to the initial delegate so that when we push or pop..
// ..this view controller we can appropriately assign back the original delegate
initialInteractivePopGestureRecognizerDelegate = self.navigationController?.interactivePopGestureRecognizer?.delegate
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(true)
// we must set the delegate to nil whether we are popping or pushing to..
// ..this view controller, thus we set it in viewWillAppear()
self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
override func viewWillDisappear(_ animated: Bool)
super.viewWillDisappear(true)
// and every time we leave this view controller we must set the delegate back..
// ..to what it was originally
self.navigationController?.interactivePopGestureRecognizer?.delegate = initialInteractivePopGestureRecognizerDelegate
其他答案建议仅将委托设置为零。向后滑动到导航堆栈上的初始视图控制器会导致禁用所有手势。也许是对 UIKit/UIGesture 开发者的某种疏忽。
同样,我在这里实现的一些答案导致了非标准的苹果导航行为(具体来说,允许在向后滑动的同时向上或向下滚动)。这些答案似乎也有点冗长,在某些情况下是不完整的。
【讨论】:
viewDidLoad()
不是捕获initialInteractivePopGestureRecognizerDelegate
的好地方,因为navigationController
在那里可能为零(尚未推入堆栈)。 viewWillAppear
你隐藏导航栏的地方会更合适
谢谢,以上所有答案中最好的和简单的解决方案【参考方案7】:
在Hunter Maximillion Monk's answer 的基础上,我为 UINavigationController 创建了一个子类,然后在我的故事板中为我的 UINavigationController 设置了自定义类。这两个类的最终代码如下所示:
InteractivePopRecognizer:
class InteractivePopRecognizer: NSObject
// MARK: - Properties
fileprivate weak var navigationController: UINavigationController?
// MARK: - Init
init(controller: UINavigationController)
self.navigationController = controller
super.init()
self.navigationController?.interactivePopGestureRecognizer?.delegate = self
extension InteractivePopRecognizer: UIGestureRecognizerDelegate
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
return (navigationController?.viewControllers.count ?? 0) > 1
// This is necessary because without it, subviews of your top controller can cancel out your gesture recognizer on the edge.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
return true
HiddenNavBarNavigationController:
class HiddenNavBarNavigationController: UINavigationController
// MARK: - Properties
private var popRecognizer: InteractivePopRecognizer?
// MARK: - Lifecycle
override func viewDidLoad()
super.viewDidLoad()
setupPopRecognizer()
// MARK: - Setup
private func setupPopRecognizer()
popRecognizer = InteractivePopRecognizer(controller: self)
故事板:
【讨论】:
【参考方案8】:看起来@ChrisVasseli 提供的解决方案是最好的。我想在 Objective-C 中提供相同的解决方案,因为问题是关于 Objective-C(见标签)
@interface InteractivePopGestureDelegate : NSObject <UIGestureRecognizerDelegate>
@property (nonatomic, weak) UINavigationController *navigationController;
@property (nonatomic, weak) id<UIGestureRecognizerDelegate> originalDelegate;
@end
@implementation InteractivePopGestureDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
if (self.navigationController.navigationBarHidden && self.navigationController.viewControllers.count > 1)
return YES;
else
return [self.originalDelegate gestureRecognizer:gestureRecognizer shouldReceiveTouch:touch];
- (BOOL)respondsToSelector:(SEL)aSelector
if (aSelector == @selector(gestureRecognizer:shouldReceiveTouch:))
return YES;
else
return [self.originalDelegate respondsToSelector:aSelector];
- (id)forwardingTargetForSelector:(SEL)aSelector
return self.originalDelegate;
@end
@interface NavigationController ()
@property (nonatomic) InteractivePopGestureDelegate *interactivePopGestureDelegate;
@end
@implementation NavigationController
- (void)viewDidLoad
[super viewDidLoad];
self.interactivePopGestureDelegate = [InteractivePopGestureDelegate new];
self.interactivePopGestureDelegate.navigationController = self;
self.interactivePopGestureDelegate.originalDelegate = self.interactivePopGestureRecognizer.delegate;
self.interactivePopGestureRecognizer.delegate = self.interactivePopGestureDelegate;
@end
【讨论】:
因为ObjC还没有死! ? 这是正确的解决方案。任何其他不转发给原始委托的解决方案都是不正确的。【参考方案9】:我的解决方案是直接扩展UINavigationController
类:
import UIKit
extension UINavigationController: UIGestureRecognizerDelegate
override open func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
self.interactivePopGestureRecognizer?.delegate = self
public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
return self.viewControllers.count > 1
这样,所有导航控制器都可以通过滑动关闭。
【讨论】:
奇怪的是,这会导致所有对属于任何导航控制器的 VC 的viewDidAppear
调用都被忽略。【参考方案10】:
Hunter Monk 的回答真的很牛逼,可惜在 iOS 13.3.1 中就不行了。
我将解释另一种隐藏UINavigationBar
而不会丢失swipe to back gesture
的方法。
我已经在 iOS 13.3.1 和 12.4.3 上进行了测试,并且可以正常工作。
您需要创建一个UINavigationController
的自定义类,并将该类设置为Storyboard
中的UINavigationController
不要在Storyboard
上隐藏NavigationBar
Storyboard
上的示例:
最后,把这个:navigationBar.isHidden = true
放在 viewDidLoad
的 CustomNavigationController
类中。
请确保不要使用此方法setNavigationBarHidden(true, animated: true)
来隐藏NavigationBar
。
import UIKit
class CustomNavigationController: UINavigationController
override func viewDidLoad()
super.viewDidLoad()
navigationBar.isHidden = true
【讨论】:
我已经在真机 iPhone 6S Plus 上使用iOS 13.4.1
进行了测试,然后滑动回来工作。
不错的解决方案,在 iOS 14.5 (beta 2) 上测试并且仍然有效。请记住,preferredStatusBarStyle 将不再在视图控制器中调用。它必须由自定义导航控制器处理。【参考方案11】:
您可以使用代理委托来完成。在构建导航控制器时,获取现有的委托。并将其传递给代理。然后使用forwardingTargetForSelector:
将除gestureRecognizer:shouldReceiveTouch:
之外的所有委托方法传递给现有委托
设置:
let vc = UIViewController(nibName: nil, bundle: nil)
let navVC = UINavigationController(rootViewController: vc)
let bridgingDelegate = ProxyDelegate()
bridgingDelegate.existingDelegate = navVC.interactivePopGestureRecognizer?.delegate
navVC.interactivePopGestureRecognizer?.delegate = bridgingDelegate
代理委托:
class ProxyDelegate: NSObject, UIGestureRecognizerDelegate
var existingDelegate: UIGestureRecognizerDelegate? = nil
override func forwardingTargetForSelector(aSelector: Selector) -> AnyObject?
return existingDelegate
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool
return true
【讨论】:
这个答案是真正的Obj-C风格! forwardingTargetForSelector 如果我知道过去的项目,我会节省很多时间。好东西!【参考方案12】:Xamarin 答案:
在 ViewController 的类定义中实现 IUIGestureRecognizerDelegate
接口:
public partial class myViewController : UIViewController, IUIGestureRecognizerDelegate
在您的 ViewController 中添加以下方法:
[Export("gestureRecognizerShouldBegin:")]
public bool ShouldBegin(UIGestureRecognizer recognizer)
if (recognizer is UIScreenEdgePanGestureRecognizer &&
NavigationController.ViewControllers.Length == 1)
return false;
return true;
在您的 ViewController 的 ViewDidLoad()
中添加以下行:
NavigationController.InteractivePopGestureRecognizer.Delegate = this;
【讨论】:
大概这是在UINavigationController
的根视图控制器中?当我尝试这个时,我得到了EXEC_BAD_ACCESS
。
你能在根视图控制器上进行边缘平移吗?这应该是不可能的,因为当你在根 VC 时,你已经弹出了所有其他 VC,并且你的 Nav 的 VC 数组的长度应该是 1。
崩溃发生在调用gestureRecognizerShouldBegin:
之前。
您可以在新问题或 Xamarin 论坛上发布您的 VC 代码吗?
不,我没有。我想我会把它留到 0.1!【参考方案13】:
我试过了,效果很好: How to hide Navigation Bar without losing slide-back ability
这个想法是在你的 .h 中实现“UIGestureRecognizerDelegate” 并将其添加到您的 .m 文件中。
- (void)viewWillAppear:(BOOL)animated
// hide nav bar
[[self navigationController] setNavigationBarHidden:YES animated:YES];
// enable slide-back
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
return YES;
【讨论】:
【参考方案14】:这是我的解决方案: 我正在更改导航栏上的 alpha,但导航栏没有隐藏。 我所有的视图控制器都是我的 BaseViewController 的子类,我有:
override func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
navigationController?.navigationBar.alpha = 0.0
您也可以继承 UINavigationController 并将该方法放在那里。
【讨论】:
【参考方案15】:TLDR-没有任何副作用的解决方案:
不要从故事板创建 UINavigationController,而是创建一个继承 UINavigationController 的自定义类并通过代码呈现它。
class RootNavigationController: UINavigationController
override func viewDidLoad()
super.viewDidLoad()
self.navigationBar.isHidden = true
let rootNavVC = RootNavigationController(rootViewController: vc)
if let appDelegate = UIApplication.shared.delegate as? AppDelegate
appDelegate.window?.rootViewController = rootNavVC
尝试了其他解决方案:
interactivePopGestureRecognizer.delegate = nil 导致随机行为。
设置 interactivePopGestureRecognizer.delegate = self 然后在 viewDidAppear 或其他地方执行此操作。
如果 navigationController?.viewControllers.count ?? 0 > 1 navigationController?.interactivePopGestureRecognizer?.isEnabled = true 别的 navigationController?.interactivePopGestureRecognizer?.isEnabled = false
只要堆栈中有 1 个以上的视图控制器,它就可以正常工作。如果计数
【讨论】:
【参考方案16】:Some people 通过使用动画YES
调用setNavigationBarHidden
方法取得了成功。
【讨论】:
我没有运气。更新我的答案以涵盖此建议。【参考方案17】:在没有导航栏的视图控制器中,我使用
open override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
CATransaction.begin()
UIView.animate(withDuration: 0.25, animations: [weak self] in
self?.navigationController?.navigationBar.alpha = 0.01
)
CATransaction.commit()
open override func viewWillDisappear(_ animated: Bool)
super.viewWillDisappear(animated)
CATransaction.begin()
UIView.animate(withDuration: 0.25, animations: [weak self] in
self?.navigationController?.navigationBar.alpha = 1.0
)
CATransaction.commit()
在交互式关闭期间,后退按钮会发光,这就是我隐藏它的原因。
【讨论】:
【参考方案18】:有一个非常简单的解决方案,我尝试过并且效果很好,它在 Xamarin.iOS 中,但也可以应用于本机:
public override void ViewWillAppear(bool animated)
base.ViewWillAppear(animated);
this.NavigationController.SetNavigationBarHidden(true, true);
public override void ViewDidAppear(bool animated)
base.ViewDidAppear(animated);
this.NavigationController.SetNavigationBarHidden(false, false);
this.NavigationController.NavigationBar.Hidden = true;
public override void ViewWillDisappear(bool animated)
base.ViewWillDisappear(animated);
this.NavigationController.SetNavigationBarHidden(true, false);
【讨论】:
【参考方案19】:以下是当用户滑出 ViewController 时如何禁用手势识别器。您可以将其粘贴到 viewWillAppear() 或 ViewDidLoad() 方法上。
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
【讨论】:
请在发布答案之前阅读问题。问题是关于启用它,而不是禁用它。我们喜欢流行的手势。以上是关于在 UINavigationController 中隐藏导航栏时不向后滑动的主要内容,如果未能解决你的问题,请参考以下文章
在 UINavigationController 内的 UITabBarcontroller 中添加 UINavigationController?
从嵌入在 UINavigationController 中的一个视图控制器到另一个 UINavigationController
(Swift) 在嵌套在 Main UINavigationController 中的 UINavigationController 和 UITabController 之间切换
关闭 UINavigationController 并呈现另一个 UINavigationController
带有主 UINavigationController 和详细 UINavigationController 的 UISplitViewcontroller