[英]Replace a UIViewController in the UINavigationController hierarchy
我有一个 iPhone 应用程序,它使用UINavigationController
的标准实现来进行应用程序导航。
我试图找出一种方法来替换层次结构中的视图控制器。 换句话说,我的应用程序加载到rootViewController
,当用户按下按钮时,应用程序会推送到firstViewController
。 然后用户按下另一个按钮将应用程序导航到secondViewController
。 再次使用向下导航到另一个视图控制器,thirdViewController。 但是,我希望第三个thirdViewController
的BackButton 弹回firstViewController。
本质上,当用户推送到thirdViewController
,我希望它替换导航层次结构中的secondViewController
。
这可能吗? 我知道它正在使用 Three20,但我不是在这种情况下。 尽管如此,如果可以在 Three20 中实现,那么它当然应该使用直接的 SDK 调用。 有人有想法吗?
干杯,布雷特
很简单,当即将推,而不是做一个简单的thirdViewController pushViewController
做到这一点:
NSArray * viewControllers = [self.navigationController viewControllers];
NSArray * newViewControllers = [NSArray arrayWithObjects:[viewControllers objectAtIndex:0], [viewControllers objectAtIndex:1], thirdController,nil];
[self.navigationController setViewControllers:newViewControllers];
其中[viewControllers objectAtIndex:0]
和[viewControllers objectAtIndex:1]
是您的 rootViewController 和您的 FirstViewController。
NSMutableArray *viewController = [NSMutableArray arrayWithArray:[navController viewControllers]];
[viewController replaceObjectAtIndex:1 withObject:replacementController];
[navController setViewControllers:viewController];
有关更多信息,请参阅UINavigationController 类参考。
Swift 中更简洁的方法应该是:
extension UINavigationController {
func replaceTopViewController(with viewController: UIViewController, animated: Bool) {
var vcs = viewControllers
vcs[vcs.count - 1] = viewController
setViewControllers(vcs, animated: animated)
}
}
如果您只是替换导航控制器视图控制器数组中的viewController
,则无法为过渡设置动画。 我建议在第三个视图控制器的viewWillAppear
方法中执行以下操作。
-(void) viewWillAppear:(BOOL)animated
{
NSArray *vCs=[[self navigationController] viewControllers];
NSMutableArray *nvCs=nil;
//remove the view controller before the current view controller
nvCs=[[NSMutableArray alloc]initWithArray:vCs];
[nvCs removeObjectAtIndex:([nvCs count]-2)];
[[self navigationController] setViewControllers:nvCs];
[super viewWillAppear:animated];
}
斯威夫特 4 版本:
if var viewControllers = navigationController?.viewControllers {
viewControllers[viewControllers.count - 1] = newViewController
navigationController?.viewControllers = viewControllers
}
由于您只是尝试从 ViewControllers 堆栈中弹出两次,因此您可以通过调用获得相同的结果
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
从第三个thirdViewController
的后退按钮
- (void)swapTopViewController:(UIViewController *)topViewController{
NSArray *viewControllers = [self.navigationController viewControllers];
NSMutableArray *editableViewControllers = [NSMutableArray arrayWithArray:viewControllers];
[editableViewControllers removeLastObject];
[editableViewControllers addObject:topViewController];
[self.navigationController setViewControllers:editableViewControllers];
}
extension UINavigationController {
func setTop(viewController: UIViewController) {
viewControllers = [viewController]
}
}
Swift 5 UINavigationController 扩展,在替换时也支持Fade
动画。
extension UINavigationController {
func find(of type: UIViewController.Type) -> UIViewController? {
for controller in self.viewControllers {
if controller.isKind(of: type) {
return controller
}
}
return nil
}
func go(to controller: UIViewController, animated: Bool = true) {
if let old = self.find(of: type(of: controller)) {
self.popToViewController(old, animated: animated)
}
else {
self.pushViewController(controller, animated: animated)
}
}
fileprivate func prepareFade() {
let transition: CATransition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.fade
view.layer.add(transition, forKey: nil)
}
func replace(to controller: UIViewController, animated: Bool = true, fade: Bool = true) {
guard let current = self.topViewController else {
return
}
var controllers = self.viewControllers
controllers.remove(current)
controllers.append(controller)
if fade {
prepareFade()
self.setViewControllers(controllers, animated: false)
}
else {
self.setViewControllers(controllers, animated: animated)
}
}
}
extension Array where Element: Equatable {
mutating func remove(_ element: Element) {
if let index = self.firstIndex(of: element) {
self.remove(at: index)
}
}
}
来自@duan 的这个答案是完美的,它会用一个新项目替换最上面的项目:
extension UINavigationController {
func replaceTopViewController(with vc: UIViewController, animated: Bool) {
var vcs = viewControllers
vcs[vcs.count - 1] = vc // NB watch for bizarre zero size
setViewControllers(vcs, animated: animated)
}
}
然而,很多时候,你会有一个“Base”控制器,你希望它一直在那里。
如果您想将所有内容安全地清除到 Base 并更改为新的(没有在 Base 中运行 viewWillAppear),则:
extension UINavigationController {
func popToRoot(andPushOnly: UIViewController) {
var vcs = viewControllers
while vcs.count > 1 { vcs.removeLast() }
if vcs.count < 1 { return }
vcs.append(andPushOnly)
setViewControllers(vcs, animated: false)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.