开发需求: 仿照“今日头条” 中文章详情页面,逻辑是这样的:push进文章详情控制器,点击相关文章,继续push进一个新的相同的详情控制器,依次下去。点击返回或右滑手势返回需直接返回到最前面的控制器(不一定是根控制器)。
需求整理:
A 控制器 文章列表页
B 控制器 文章详情页
A—>B(1) —>B(2)—>B(3)—>B(4) —> ….
无论到push了多少个B控制器,返回需直接到A控制器
实现思路
- 每次push前,先pop当前控制器,再push一个新的
示例代码:
[self.navigationController popViewControllerAnimated:YES];
NewsDetailViewController *detailVC = [NewsDetailViewController new];
[self showViewController:detailVC sender:nil];
这种实现方式无法达到预期效果,pop回后,控制器已销毁,无法push。
- 删除掉NavigationController.ViewControllers 中的当前控制器,再创建新的当前控制器,重新设置
思路参考:iOS实现先无动画pop再push,替换当前控制器
示例代码:
NewsDetailViewController *detailVC = [NewsDetailViewController new];
// 获取当前控制器数组
NSMutableArray *vcArray = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
// 获取当前控制器在数组的位置
int index = (int)[vcArray indexOfObject:self];
// 移除当前控制器器
[vcArray removeObjectAtIndex:index];
// 添加新控制器
[vcArray addObject:detailVC];
// 重新设置当前导航控制器的路由数组
[self.navigationController setViewControllers:vcArray animated:YES];
这种方式其实已经满足了需求,但是唯一的缺陷就是这种重新设置的方式不是push,与TabBar和Navigation结合的框架搭建时 TabBar的隐藏代码是 viewController.hidesBottomBarWhenPushed = YES ,只有push的时候才会起作用。
这里是可以手动隐藏TabBar,但是返回界面再显示TabBar的话,无法找到一个合理的显示时机,不符合需求。虽然问题也可通过其他方式解决,但是改动过大,不太好处理,放弃。
- 换一个思路想想,既然能重新设置NavigationController的ViewControllers,那是不是可以换一个时机来无动画地设置,神不知鬼不觉地把中间的所有详情控制器销毁掉呢?经过尝试,这个思路可行。
思路:放心的去push吧,push多少个没关系,不用管。只要我们在当前控制器里找一个时机来销毁掉上一个旧的当前控制器就可以了。经过尝试,在ViewDidLoad里销毁的话会出现界面push时明显卡顿问题。所以我是在当前控制器加载出来后销毁的,也就是界面网络请求完成后。
既然如此,那是不是就如标题所说可以 “手动销毁掉NavigationController中的任意控制器”
可能还有其他更好的方法,欢迎讨论指正!
实例代码:
//随意push 不用管
NewsDetailViewController *detailVC = [NewsDetailViewController new];
[self showViewController:detailVC sender:nil];
//销毁中间详情页控制器
- (void)dismissDetailVC
{
if (self.navigationController.viewControllers.count >= 3) {
NSMutableArray *array = self.navigationController.viewControllers.mutableCopy;
NSMutableArray *detaiArray = [NSMutableArray array];
for (UIViewController *vc in array) {
if ([vc isKindOfClass:[self class]]) {
[detaiArray addObject:vc];
}
}
if (detaiArray.count > 1) {
[array removeObject:detaiArray.firstObject];
}
[self.navigationController setViewControllers:array animated:NO];
}
}