推送UIViewController至UINavigationViewController时应用卡顿问题解决
最近我碰到了一个很头疼的iOS开发问题:给UINavigationController推送UIViewController时出现了莫名的卡顿,折腾了好一阵终于找到靠谱的解决方案,特意分享出来帮大家避坑。
Bug场景
- 不管是通过segue还是
pushViewController:方法推送页面,只要先在导航控制器的根ViewController里尝试触发滑动返回手势(正常情况下这个手势在根页面应该是无效的) - 之后点击页面元素推送新的ViewController到导航栈,App就会出现卡顿现象
- 此时用XCode截图会显示已经跳转到下一个界面,但实际界面完全没有响应;查看CPU、内存等性能指标都正常,只要再触发一次滑动返回手势就能退出卡顿状态
解决方案
这个方案尤其适合使用UITabBarController的场景,需要在你自定义的继承自UINavigationController的BaseNavigationViewController中做以下修改:
1. 遵循必要的协议
确保BaseNavigationViewController遵循UINavigationControllerDelegate和UIGestureRecognizerDelegate协议:
@interface BaseNavigationViewController : UINavigationController <UINavigationControllerDelegate, UIGestureRecognizerDelegate> @end
2. 设置导航控制器代理
在viewDidLoad方法中设置自身为导航控制器的代理:
- (void)viewDidLoad { [super viewDidLoad]; self.delegate = self; }
3. 实现代理方法
添加以下两个代理方法,动态控制滑动返回手势的可用性:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { if (self.viewControllers.count > 1) { self.interactivePopGestureRecognizer.delegate = self; self.interactivePopGestureRecognizer.enabled = YES; } else { self.interactivePopGestureRecognizer.delegate = nil; self.interactivePopGestureRecognizer.enabled = NO; } } } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { return self.viewControllers.count > 1; } return NO; }
原理说明
这个方案的核心是根据导航栈中ViewController的数量,动态启用/禁用滑动返回手势:当处于根页面时(栈中只有1个控制器),直接禁用滑动返回手势,避免无效的手势触发干扰后续的页面推送逻辑,从根源上解决了卡顿问题。
内容的提问来源于stack exchange,提问作者Aliunco
相关产品推荐
相关产品推荐

