2

我们试图弄清楚当向后导航时如何有条件地排除我们的后台堆栈中的某些屏幕。例如,采取以下屏幕:

  1. 主仪表板(您可以从这里转到 2 或 3)
  2. 订单管理(您可以从这里转到 3 或 6)
  3. 输入订单
  4. 查看订单
  5. 订单确认(如果您在此处完成,则后面应跳过 3 和 4)
  6. 订单状态(如果您在此处完成,则返回应跳过 5(它已经跳过 3 和 4))

屏幕 3-5 代表输入订单,因此如果您已进入确认页面,我们不希望您返回查看或编辑页面。

出于同样的原因,如果您从确认页面导航到“订单状态”,我们不希望您导航回“订单确认”,而是返回“订单管理”或“主仪表板”(取决于关于你是如何到达那里的)

注意:我们知道 popToViewController 以及它如何让您跳过您所在位置和您指定的控制器之间的所有控制器。问题是我不知道那个视图控制器是什么。我只知道我想跳过哪个(如果它们存在的话)。更重要的是,后退按钮反映了堆栈中的内容,而不是我要弹出的内容。这就是为什么我希望告诉系统“返回时忽略堆栈中的这些”。希望这是有道理的。

我的粗略尝试是像这样修改后堆栈...

func showConfirmation() {

    guard navigationController = navigationController else {
        return
    }

    navigationController.pushViewController(orderConfirmation, animated:true)

    if let orderEntryIndex  = navigationController.viewControllers.index(of:orderEntry),
       let orderReviewIndex = navigationController.viewControllers.index(of:orderReview){

        navigationController.viewControllers.removeSubrange(orderEntryIndex...orderReviewIndex)
    }
}

func showStatus() {

    guard navigationController = navigationController else {
        return
    }

    navigationController.pushViewController(orderStatus, animated:true)

    if let orderConfirmationIndex = navigationController.viewControllers.index(of:orderConfirmation){

        navigationController.viewControllers.remove(at: orderConfirmationIndex)
    }
}

注意:这是简化的代码。我们实际上并没有挂在视图控制器的实例上。我们通过在后台堆栈中查找它们的类型来找到索引。这仅用于简单说明目的。

当导航工作时,在动画期间,后退按钮显示原始后退位置,然后在动画之后,标签的值“捕捉”以显示新的后退位置。这当然证明这不是正确的方法。

我知道有放松的segues,但这担心你要去哪里。我们只想在导航离开后从积压中删除项目,否则保持后台堆栈完好无损。

那么如何实现这种忽略先前步骤的行为呢?

4

2 回答 2

0

在您的条件之前,您可以检查导航堆栈中的视图控制器列表并弹出到您想要的视图控制器

    for controller in (self.navigationController?.viewControllers)! {
        if controller is SomeClass {
            self.navigationController?.popToViewController(controller, animated: true)
        }
    }
于 2018-03-08T19:46:53.677 回答
0

好的,我想出了如何做到这一点,并在 UINavigationController 上添加了一个扩展来帮助将来解决这个问题。

秘诀是使用该setViewControllers方法替换整个UIViewController对象集,删除您想要跳过的对象。为方便起见,我传入了一个UIViewController.Types 数组,用于过滤掉我不想要的现有控制器。

extension UINavigationController {

    func pushViewController(_ viewController:UIViewController, removingBackItemsOfType backItemTypesToRemove:[UIViewController.Type], animated:Bool) {

        var viewControllers = self.viewControllers
            .filter{ vc in !backItemTypesToRemove.contains(where:{ vcType in vcType == type(of:vc) } ) }

        viewControllers.append(viewController)

        setViewControllers(viewControllers, animated: animated)
    }
}

所以现在,当我在“查看订单”时,我使用这种方法推送到“订单确认”,传递我想从后台堆栈中删除的项目,就像这样......

let orderConfirmation = OrderConfirmation()

let typesToRemove:[UIViewController.Type] = [
    EnterOrder.self,
    ReviewOrder.self
]

navigationController?.pushViewController(orderConfirmation, removingBackItemsOfType:typesToRemove, animated:true)

结果是它推送到新的 Order Confirmation 视图控制器,但按下返回会将我带到输入订单之前的任何屏幕,无论我来自哪里。

然后我在从订单确认推送到订单状态时做同样的事情,这次删除[OrderConfirmation.self]. 同样的事情......现在回到让我进入订单输入的屏幕。

简而言之,这使您可以设置我上面描述的场景,而不必担心之前发生了什么。正是你想跳过的。

希望这可以帮助!

于 2018-03-08T21:31:05.690 回答