如何识别导航堆栈中的前一个视图控制器

Posted

技术标签:

【中文标题】如何识别导航堆栈中的前一个视图控制器【英文标题】:How to identify previous view controller in navigation stack 【发布时间】:2011-10-23 18:18:42 【问题描述】:

我有两个单独的navigationcontrollers,一个是RootViewController A,另一个是RootViewController B。

我可以将ViewController C 推送到 A 或 B 的导航堆栈中。

问题:当我在ViewControllerC 中时,如何知道我是在属于A 还是B 的堆栈中?

【问题讨论】:

为什么不直接在 C 上创建一个 previousViewController 属性,在推送 C 时设置它?还是在推送时从 A 或 B 向 C 提供所需的信息? @TerryWilcox ,'因为现在的关系可能非常复杂 【参考方案1】:

更简洁的 Swift 实现:

extension UIViewController 
    var previousViewController: UIViewController? 
        guard let nav = self.navigationController,
              let myIdx = nav.viewControllers.index(of: self) else 
            return nil
        
        return myIdx == 0 ? nil : nav.viewControllers[myIdx-1]
    

【讨论】:

【参考方案2】:

您可以使用UINavigationControllerviewControllers 属性:

@property(nonatomic, copy) NSArray *viewControllers

讨论:根视图控制器在数组中的索引 0 处,后视图控制器在索引 n-2 处,顶部控制器在索引 n-1 处,其中 n 是数组中的项目数。

https://developer.apple.com/documentation/uikit/uinavigationcontroller

您可以使用它来测试根视图控制器(数组索引为 0 的那个)是视图控制器 A 还是 B。

【讨论】:

如何在 SWIFT 中将其作为字符串获取。(我是 swift 新手) @cyberboy 同样简单:使用var viewControllers: [UIViewController] 上一个视图控制器将位于viewControllers.last @Burak viewControllers.last 有当前的视图控制器,为了获得以前的视图控制器,应该使用viewControllers[viewControllers.count-2]【参考方案3】:

对于 swift 3,您可以这样做:

var backtoViewController:UIViewController!
for viewController in (self.navigationController?.viewControllers)!.reversed() 
    if viewController is NameOfMyDestinationViewController 
            backtoViewController = viewController
    

self.navigationController!.popToViewController(backtoViewController, animated: true)

您只需要将“NameOfMyDestinationViewController”替换为您要返回的viewController。

【讨论】:

【参考方案4】:

我的扩展,swift 3

extension UIViewController 
    var previousViewController: UIViewController? 
        guard let controllers = navigationController?.viewControllers, controllers.count > 1 else  return nil 
        switch controllers.count 
        case 2: return controllers.first
        default: return controllers.dropLast(2).first
        
    

【讨论】:

【参考方案5】:

作为UINavigationController 扩展:

extension UINavigationController 

    func previousViewController() -> UIViewController? 
        guard viewControllers.count > 1 else 
            return nil
        
        return viewControllers[viewControllers.count - 2]
    


【讨论】:

【参考方案6】:

使用 Swift 使用守卫。

extension UIViewController 

    func getPreviousViewController() -> UIViewController? 
        guard let _ = self.navigationController else 
            return nil
        

        guard let viewControllers = self.navigationController?.viewControllers else 
            return nil
        

        guard viewControllers.count >= 2 else 
            return nil
                
        return viewControllers[viewControllers.count - 2]
    

【讨论】:

【参考方案7】:

这是Prabhu Beeman's Swift 代码的修改版本,它对其进行了调整以支持 Swift 3:

extension UIViewController 
    func backViewController() -> UIViewController? 
        if let stack = self.navigationController?.viewControllers 
            for i in (1..<stack.count).reverse() 
                if(stack[i] == self) 
                    return stack[i-1]
                
            
        
        return nil
    

【讨论】:

一些注意事项:reverse() 现在是 reversed() 并且 self.navigationController?.viewControllers 永远不会包含“self”视图控制器,所以 return stack.last 应该足够了【参考方案8】:

Swift 2.2 的实现 - 将此添加到 UIViewController 扩展中。从某种意义上说是安全的,如果视图控制器是 rootvc 或不在导航控制器中,它将返回 nil

var previousViewController: UIViewController? 
  guard let viewControllers = navigationController?.viewControllers else 
    return nil
  
  var previous: UIViewController?
  for vc in viewControllers
    if vc == self 
      break
    
    previous = vc
  
  return previous

【讨论】:

【参考方案9】:

tjklemz 代码作为扩展的 Swift 实现:

extension UIViewController 

    func backViewController() -> UIViewController?         
        if let stack = self.navigationController?.viewControllers 
            for(var i=stack.count-1;i>0;--i) 
                if(stack[i] == self) 
                    return stack[i-1]
                
            
        
        return nil
    

【讨论】:

我已经发布了这个代码的修改版本,它在下面作为新的答案支持 Swift 3。【参考方案10】:

因为死马喜欢被打:)

- (UIViewController *)previousViewController

    NSArray *vcStack = self.navigationController.viewControllers;
    NSInteger selfIdx = [vcStack indexOfObject:self];
    if (vcStack.count < 2 || selfIdx == NSNotFound)  return nil; 
    return (UIViewController *)[vcStack objectAtIndex:selfIdx - 1];

【讨论】:

【参考方案11】:

查找前一个视图控制器很简单。

在您的情况下,即您在 C 中并且您需要 B,[self.navigationController.viewControllers lastObject] 就是您想要的。

对于A来说,由于A是根视图控制器,只需将lastObject替换为firstObject即可获得。

【讨论】:

【参考方案12】:

@tjklemz 代码的 Swift 实现:

var backViewController : UIViewController? 

        var stack = self.navigationController!.viewControllers as Array

        for (var i = stack.count-1 ; i > 0; --i) 
            if (stack[i] as UIViewController == self) 
                return stack[i-1] as? UIViewController
            

        
        return nil
    

【讨论】:

我怎样才能把它作为一个字符串..(我是 swift 新手) @cyberboy 你好!我不确定我是否理解你的问题。您想将 backViewController 描述作为字符串吗?如果是这样,您可以考虑println("backViewController is: \(backViewController.description)");这会给你一个类似“UINavigationController: 0x7fcea1d286b0”的描述,不是很清楚,但至少可以让你识别对象。正如我所说,我不确定你到底需要什么......【参考方案13】:
- (UIViewController *)backViewController

    NSInteger myIndex = [self.navigationController.viewControllers indexOfObject:self];

    if ( myIndex != 0 && myIndex != NSNotFound ) 
        return [self.navigationController.viewControllers objectAtIndex:myIndex-1];
     else 
        return nil;
    

【讨论】:

【参考方案14】:

已接受答案的更通用实现:

- (UIViewController *)backViewController 
    NSArray * stack = self.navigationController.viewControllers;

    for (int i=stack.count-1; i > 0; --i)
        if (stack[i] == self)
            return stack[i-1];

    return nil;

这将返回正确的“后视图控制器”,无论当前类在导航堆栈中的什么位置。

【讨论】:

【参考方案15】:

这是接受的答案的实现:

- (UIViewController *)backViewController

    NSInteger numberOfViewControllers = self.navigationController.viewControllers.count;

    if (numberOfViewControllers < 2)
        return nil;
    else
        return [self.navigationController.viewControllers objectAtIndex:numberOfViewControllers - 2];

【讨论】:

我建议将此作为类别添加到UIViewController【参考方案16】:

访问viewControllers 属性的n-2 元素以访问父视图控制器。

获得该实例后,您可以通过记录NSStringFromClass() 函数的结果来检查其类型。或者,您可以在控制器 A 和 B 中保留一些 static const 标识符字符串,以及打印出字符串的 getter 函数。

【讨论】:

获取视图控制器当前索引的任何简单方法,或者我应该根据我的层次结构对它们进行硬编码。【参考方案17】:

使用navigationController 方法检索它。见documentation on Apple's site。

navigationController 作为导航的父级或祖先 控制器。 (只读)

@property(非原子,只读,保留) UINavigationController *导航控制器

讨论 如果视图只返回一个导航控制器 控制器在其堆栈中。如果导航,则此属性为零 找不到控制器。

可用性适用于 ios 2.0 及更高版本。

【讨论】:

以上是关于如何识别导航堆栈中的前一个视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

如何从导航堆栈中的任何位置弹出到任意视图控制器

如何快速隐藏嵌入在导航堆栈中的视图控制器中的选项卡栏?

如何实现“向右拖动以关闭”导航堆栈中的视图控制器?

从导航堆栈中删除视图控制器

TabBar 覆盖导航堆栈中的视图控制器内容

如何展开到导航堆栈上的第一个视图控制器