隐藏NavigationController栈中UIViewController实现无感知跳转
可行实现方案
以下方案按改动量从小到大排序,均适配老旧Objective-C项目,无需迁移controller2已有业务逻辑。
方案1:无动画透明push/pop(改动最小)
之前出现黑页的核心原因是开启了转场动画、未配置controller2视图透明,按以下步骤调整即可:
- push和pop全程关闭动画,所有
animated参数传NO - push前将controller2的view背景色设为完全透明
- 若controller2内部有修改导航栏显隐、tabbar显隐的逻辑,提前通过方法交换或者子类重写的方式屏蔽,避免导航栏位移
核心代码:
// push阶段 controller2.view.backgroundColor = [UIColor clearColor]; [self.navigationController pushViewController:controller2 animated:NO]; // controller2任务完成后pop阶段 [self.navigationController popViewControllerAnimated:NO];
该方案不会触发转场动画漏黑底,透明配置下用户全程只能看到controller1的视图。
方案2:子控制器嵌入(零UI风险,推荐)
如果方案1仍存在导航栏跳动、偶现闪屏问题,直接用子控制器方案,完全不走导航栈转场、不走模态弹出,从根源避免所有UI异常:
- 不修改导航栈结构,将controller2作为controller1的子控制器挂载,不把controller2的view添加到任何可见视图层级
- 手动触发controller2的完整生命周期回调,保证其内部业务逻辑正常执行
- 任务执行完成后移除子控制器即可,全程不会对controller1的视图造成任何修改
核心代码:
// 初始化并挂载子控制器 [self addChildViewController:controller2]; [controller2 didMoveToParentViewController:self]; // 触发入场生命周期,保证viewDidLoad、viewWillAppear、viewDidAppear等回调正常执行 [controller2 beginAppearanceTransition:YES animated:NO]; [controller2 endAppearanceTransition]; // --- controller2执行自身任务 --- // 任务完成后,触发出场生命周期 [controller2 beginAppearanceTransition:NO animated:NO]; [controller2 endAppearanceTransition]; // 移除子控制器 [controller2 willMoveToParentViewController:nil]; [controller2 removeFromParentViewController];
该方案完全不会出现黑页、视图挤压问题,不需要修改controller1原有业务逻辑,也不需要迁移controller2的已有代码,适配大代码量的老旧控制器场景。
原有方案问题原因说明
- 常规push/pop出现黑页:开启动画转场时系统会临时将controller1的视图移出窗口,controller2的view默认背景为黑色,透明配置缺失就会露出黑底
- 模态弹出出现视图向下挤压:
UIModalPresentationCurrentContext在iOS早期版本中会自动调整底层presenting控制器的view的frame,触发自动布局更新,最终导致视图位置偏移。
内容的提问来源于stack exchange,提问作者Aleem
相关产品推荐
相关产品推荐

