OS原生是支援邊緣滑動返回的,
但如QQ這種全屏全域性右劃返回顯然使用者體驗更好,
實現起來其實也不麻煩, 但新增這個功能後可能會導致介面卡死問題,
網上的說法有很多而且不全, 其實導致這種問題會有很多種情況, 這裡總結一下:
卡死的原因有三種:
1.在push或pop的過程中, 接收到新的滑動返回手勢.
主要是介面切換快速操作可能出現
解決辦法:
自定義UINavigationController,
在pushViewController/setViewControllers/popViewControllerAnimated/popToRootViewControllerAnimated中禁用手勢
在代理方法- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;中啟用手勢
複製程式碼
2.在根控制器右劃返回
在上面的程式碼中增加判斷, 若子控制器數量為1, 禁用手勢
複製程式碼
3.點選navigationItem返回同時觸發了手勢.
一般在自定義了返回按鈕出現, 例如:自定義button的手勢為UIControlEventTouchDown, 全域性右劃返回手勢作用view為self.interactivePopGestureRecognizer.view, 兩者可能會同時觸發
根據原因, 改變手勢作用域
UIView *targetView = [[self.viewControllers lastObject] view];
或改變按鈕事件觸發條件
UIControlEventTouchUpInside
複製程式碼
完整新增全域性右滑返回且無BUG程式碼如下:
@interface LTNavigationController () <UIGestureRecognizerDelegate, UINavigationControllerDelegate>
/**
是否允許右滑返回
*/
@property (nonatomic, assign, getter=isBackGestureEnable) BOOL backGestureEnable;
@end
@implementation LTNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationBar.backgroundColor = [UIColor whiteColor];
//設定全域性右滑返回
[self setupRightPanReturn];
[self.navigationItem setHidesBackButton:YES];
self.delegate = self;
}
#pragma mark ---每次push之後生成返回按鈕----
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
if (self.viewControllers.count > 0) {
viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem BarButtonItemWithImg:@"back_black" highlightedImg:nil target:self action:@selector(popViewController)];
viewController.hidesBottomBarWhenPushed = YES;
viewController.edgesForExtendedLayout = UIRectEdgeNone;
viewController.automaticallyAdjustsScrollViewInsets = NO;
}
// push的時候禁用手勢
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.interactivePopGestureRecognizer.enabled = NO;
self.backGestureEnable = NO;
}
[super pushViewController:viewController animated:animated];
}
- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated{
for (UIViewController *viewController in viewControllers) {
if (viewController != [viewControllers firstObject]) {
viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem BarButtonItemWithImg:@"back_black" highlightedImg:nil target:self action:@selector(popViewController)];
viewController.hidesBottomBarWhenPushed = YES;
viewController.edgesForExtendedLayout = UIRectEdgeNone;
viewController.automaticallyAdjustsScrollViewInsets = NO;
}
}
// push的時候禁用手勢
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.interactivePopGestureRecognizer.enabled = NO;
self.backGestureEnable = NO;
}
[super setViewControllers:viewControllers animated:animated];
}
- (void)popViewController{
[self popViewControllerAnimated:YES];
}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated{
// pop的時候禁用手勢
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.interactivePopGestureRecognizer.enabled = NO;
}
return [super popViewControllerAnimated:animated];
}
- (NSArray<UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated{
// pop的時候禁用手勢
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.interactivePopGestureRecognizer.enabled = NO;
}
return [super popToRootViewControllerAnimated:animated];
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
// push完成後的時候判斷是否在根控制器啟用手勢
if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
if ([navigationController.viewControllers count] == 1) {
navigationController.interactivePopGestureRecognizer.enabled = NO;
} else {
self.backGestureEnable = YES;
navigationController.interactivePopGestureRecognizer.enabled = YES;
}
}
}
#pragma mark ---處理全域性右滑返回---
- (void)setupRightPanReturn{
// 獲取系統自帶滑動手勢的target物件
id target = self.interactivePopGestureRecognizer.delegate;
// 獲取返回方法
SEL handler = NSSelectorFromString(@"handleNavigationTransition:");
// 獲取新增系統邊緣觸發手勢的View
UIView *targetView = self.interactivePopGestureRecognizer.view;
// 建立pan手勢 作用範圍是全屏
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:handler];
pan.delegate = self;
[targetView addGestureRecognizer:pan];
// 關閉邊緣觸發手勢 防止和原有邊緣手勢衝突
[self.interactivePopGestureRecognizer setEnabled:NO];
}
// 什麼時候呼叫:每次觸發手勢之前都會詢問下代理,是否觸發。
// 作用:攔截手勢觸發
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer{
//解決與左滑手勢衝突
CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view];
if (translation.x <= 0 || !self.isBackGestureEnable) {
return NO;
}
return self.childViewControllers.count == 1 ? NO : YES;
}
複製程式碼