下一篇相关文章:UINavigationBar手势侧滑、隐藏bar、UIScrollView侧滑返回研究二
前言
iOS开发中都会遇到的一个问题,就是在iOS7以后苹果自动添加了侧滑pop返回手势,但一般APP由于设计的需要,会修改苹果的backBarButtonItem或是leftBarButtonItem,但只要修改这个就会导致苹果定义的这个侧滑pop返回的手势失效,于是就有了以下多种八仙过海各显神通的解决方式
-
方案一
作者:J_雨
demo:TestPopGestureSolution1
介绍文章: iOS利用Runtime自定义控制器POP手势动画
- 方法一:
这篇文章介绍了2种方法,方法一是利用苹果推荐的做法,就是重写UINavigationController的两个代理方法,navigationController:animationControllerForOperation:fromViewController:toViewController:
(返回一个处理交互的类)
navigationController:interactionControllerForAnimationController:
同时获取UINavigationController的interactivePopGestureRecognizer
,并获取这个pop手势的View,然后给这个View添加新的手势处理
UIGestureRecognizer *gesture = self.interactivePopGestureRecognizer;
gesture.enabled = NO;
UIView *gestureView = gesture.view;
UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];
popRecognizer.delegate = self;
popRecognizer.maximumNumberOfTouches = 1;
[gestureView addGestureRecognizer:popRecognizer];
_navT = [[NavigationInteractiveTransition alloc] initWithViewController:self];
[popRecognizer addTarget:_navT action:@selector(handleControllerPop:)];
具体手势的处理以及UINavigationController的代理都在NavigationInteractiveTransition
中
#import "NavigationInteractiveTransition.h"
#import "PopAnimation.h"
@interface NavigationInteractiveTransition ()
@property (nonatomic, weak) UINavigationController *vc;
@property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactivePopTransition;
@end
@implementation NavigationInteractiveTransition
- (instancetype)initWithViewController:(UIViewController *)vc
{
self = [super init];
if (self) {
self.vc = (UINavigationController *)vc;
self.vc.delegate = self;
}
return self;
}
/**
* 我们把用户的每次Pan手势操作作为一次pop动画的执行
*/
- (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer {
/**
* interactivePopTransition就是我们说的方法2返回的对象,我们需要更新它的进度来控制Pop动画的流程,我们用手指在视图中的位置与视图宽度比例作为它的进度。
*/
CGFloat progress = [recognizer translationInView:recognizer.view].x / recognizer.view.bounds.size.width;
/**
* 稳定进度区间,让它在0.0(未完成)~1.0(已完成)之间
*/
progress = MIN(1.0, MAX(0.0, progress));
if (recognizer.state == UIGestureRecognizerStateBegan) {
/**
* 手势开始,新建一个监控对象
*/
self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
/**
* 告诉控制器开始执行pop的动画
*/
[self.vc popViewControllerAnimated:YES];
}
else if (recognizer.state == UIGestureRecognizerStateChanged) {
/**
* 更新手势的完成进度
*/
[self.interactivePopTransition updateInteractiveTransition:progress];
}
else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
/**
* 手势结束时如果进度大于一半,那么就完成pop操作,否则重新来过。
*/
if (progress > 0.5) {
[self.interactivePopTransition finishInteractiveTransition];
}
else {
[self.interactivePopTransition cancelInteractiveTransition];
}
self.interactivePopTransition = nil;
}
}
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
/**
* 方法1中判断如果当前执行的是Pop操作,就返回我们自定义的Pop动画对象。
*/
if (operation == UINavigationControllerOperationPop)
return [[PopAnimation alloc] init];
return nil;
}
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
/**
* 方法2会传给你当前的动画对象animationController,判断如果是我们自定义的Pop动画对象,那么就返回interactivePopTransition来监控动画完成度。
*/
if ([animationController isKindOfClass:[PopAnimation class]])
return self.interactivePopTransition;
return nil;
}
@end
具体的动画在PopAnimation
,改类实现UIViewControllerAnimatedTransitioning
这个转场动画协议
具体实现
#import "PopAnimation.h"
@interface PopAnimation ()
@property (nonatomic, strong) id <UIViewControllerContextTransitioning> transitionContext;
@end
@implementation PopAnimation
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
//这个方法返回动画执行的时间
return 0.25;
}
/**
* transitionContext你可以看作是一个工具,用来获取一系列动画执行相关的对象,并且通知系统动画是否完成等功能。
*/
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
/**
* 获取动画来自的那个控制器
*/
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
/**
* 获取转场到的那个控制器
*/
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
/**
* 转场动画是两个控制器视图时间的动画,需要一个containerView来作为一个“舞台”,让动画执行。
*/
UIView *containerView = [transitionContext containerView];
[containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
NSTimeInterval duration = [self transitionDuration:transitionContext];
/**
* 执行动画,我们让fromVC的视图移动到屏幕最右侧
*/
[UIView animateWithDuration:duration animations:^{
fromViewController.view.transform = CGAffineTransformMakeTranslation([UIScreen mainScreen].bounds.size.width, 0);
}completion:^(BOOL finished) {
/**
* 当你的动画执行完成,这个方法必须要调用,否则系统会认为你的其余任何操作都在动画执行过程中。
*/
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];
// _transitionContext = transitionContext;
//----------------pop动画一-------------------------//
/*
[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:containerView cache:YES];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:)];
[UIView commitAnimations];//提交UIView动画
[containerView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
*/
//----------------pop动画二-------------------------//
/*
CATransition *tr = [CATransition animation];
tr.type = @"cube";
tr.subtype = @"fromLeft";
tr.duration = duration;
tr.removedOnCompletion = NO;
tr.fillMode = kCAFillModeForwards;
tr.delegate = self;
[containerView.layer addAnimation:tr forKey:nil];
[containerView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
*/
}
- (void)animationDidStop:(CATransition *)anim finished:(BOOL)flag {
[_transitionContext completeTransition:!_transitionContext.transitionWasCancelled];
}
@end
- 方法二
使用Runtime+KVC的方式,给UINavigationController的interactivePopGestureRecognizer.view添加一个自定义的手势,然后处理这个手势的target-action使用系统本身处理的target-action
UIGestureRecognizer *gesture = self.interactivePopGestureRecognizer;
gesture.enabled = NO;
UIView *gestureView = gesture.view;
UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];
popRecognizer.delegate = self;
popRecognizer.maximumNumberOfTouches = 1;
[gestureView addGestureRecognizer:popRecognizer];
/**
* 获取系统手势的target数组
*/
NSMutableArray *_targets = [gesture valueForKey:@"_targets"];
/**
* 获取它的唯一对象,我们知道它是一个叫UIGestureRecognizerTarget的私有类,它有一个属性叫_target
*/
id gestureRecognizerTarget = [_targets firstObject];
/**
* 获取_target:_UINavigationInteractiveTransition,它有一个方法叫handleNavigationTransition:
*/
id navigationInteractiveTransition = [gestureRecognizerTarget valueForKey:@"_target"];
/**
* 通过前面的打印,我们从控制台获取出来它的方法签名。
*/
SEL handleTransition = NSSelectorFromString(@"handleNavigationTransition:");
/**
* 创建一个与系统一模一样的手势,我们只把它的类改为UIPanGestureRecognizer
*/
[popRecognizer addTarget:navigationInteractiveTransition action:handleTransition];
以上两种方式在使用时都需要处理已经是pop到rootViewController后的情况,以及要处理正在侧滑动画时不能继续走这个侧滑转场动画,所以作者添加了对gesture代理的判断
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
/**
* 这里有两个条件不允许手势执行,1、当前控制器为根控制器;2、如果这个push、pop动画正在执行(私有属性)
*/
return self.viewControllers.count != 1 && ![[self valueForKey:@"_isTransitioning"] boolValue];
}
作者demo链接:CustomPopAnimation
-
方案二
作者:forkingdog
demo:TestPopGestureSolution2
文章说明:一个丝滑的全屏滑动返回手势
GitHub地址:FDFullscreenPopGesture
这个库作者说是参考了上面列的J_雨的那个Runtime+KVC的天才思路,具体的实现做了更多的封装与优化,主要使用分类category的方法无侵入的给所有UINavigationController添加侧滑返回的手势,这样方便无论使用了自动有nav还是系统nav都能不做任何修改就能集成到项目中
具体的代码
分类UINavigationController(FDFullscreenPopGesture)
处理侧滑返回
分类UIViewController (FDFullscreenPopGesture)
添加几个属性,让UIViewController可以方便调用一些基本的操作
fd_interactivePopDisabled
是否禁用侧滑返回手势
fd_prefersNavigationBarHidden
隐藏或显示导航栏
fd_interactivePopMaxAllowedInitialDistanceToLeftEdge
左侧最大响应侧滑的位置
具体实现:在load方法里使用Runtime修改UINavigationController的pushViewController:animated:
方法,用fd_pushViewController:animated:
实现push,如果当前NavigationController没有添加自定义的手势,则添加手势,同时给viewController添加viewWillAppear:
、viewWillAppear:
添加执行block
- (void)fd_pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.fd_fullscreenPopGestureRecognizer]) {
// Add our own gesture recognizer to where the onboard screen edge pan gesture recognizer is attached to.
[self.interactivePopGestureRecognizer.view addGestureRecognizer:self.fd_fullscreenPopGestureRecognizer];
// Forward the gesture events to the private handler of the onboard gesture recognizer.
NSArray *internalTargets = [self.interactivePopGestureRecognizer valueForKey:@"targets"];
id internalTarget = [internalTargets.firstObject valueForKey:@"target"];
SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");
self.fd_fullscreenPopGestureRecognizer.delegate = self.fd_popGestureRecognizerDelegate;
[self.fd_fullscreenPopGestureRecognizer addTarget:internalTarget action:internalAction];
// Disable the onboard gesture recognizer.
self.interactivePopGestureRecognizer.enabled = NO;
}
// Handle perferred navigation bar appearance.
[self fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:viewController];
// Forward to primary implementation.
if (![self.viewControllers containsObject:viewController]) {
[self fd_pushViewController:viewController animated:animated];
}
}
/**
给即将要显示的Controller添加执行viewWillAppear的block和viewWillDisappear的block
@param appearingViewController 即将出现的Controller
*/
- (void)fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:(UIViewController *)appearingViewController
{
if (!self.fd_viewControllerBasedNavigationBarAppearanceEnabled) {
return;
}
__weak typeof(self) weakSelf = self;
_FDViewControllerWillAppearInjectBlock block = ^(UIViewController *viewController, BOOL animated) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf setNavigationBarHidden:viewController.fd_prefersNavigationBarHidden animated:animated];
}
};
// Setup will appear inject block to appearing view controller.
// Setup disappearing view controller as well, because not every view controller is added into
// stack by pushing, maybe by "-setViewControllers:".
appearingViewController.fd_willAppearInjectBlock = block;
UIViewController *disappearingViewController = self.viewControllers.lastObject;
if (disappearingViewController && !disappearingViewController.fd_willAppearInjectBlock) {
disappearingViewController.fd_willAppearInjectBlock = block;
}
}
/**
自定义的处理全局侧滑返回的gesture,使用runtime的方式保存变量
@return 处理返回的gesture
*/
- (UIPanGestureRecognizer *)fd_fullscreenPopGestureRecognizer
{
UIPanGestureRecognizer *panGestureRecognizer = objc_getAssociatedObject(self, _cmd);
if (!panGestureRecognizer) {
panGestureRecognizer = [[UIPanGestureRecognizer alloc] init];
panGestureRecognizer.maximumNumberOfTouches = 1;
objc_setAssociatedObject(self, _cmd, panGestureRecognizer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return panGestureRecognizer;
}
/**
处理侧滑的gesture的代理
@return 处理侧滑手势的代理
*/
- (_FDFullscreenPopGestureRecognizerDelegate *)fd_popGestureRecognizerDelegate
{
_FDFullscreenPopGestureRecognizerDelegate *delegate = objc_getAssociatedObject(self, _cmd);
if (!delegate) {
delegate = [[_FDFullscreenPopGestureRecognizerDelegate alloc] init];
delegate.navigationController = self;
objc_setAssociatedObject(self, _cmd, delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return delegate;
}
- (BOOL)fd_viewControllerBasedNavigationBarAppearanceEnabled
{
NSNumber *number = objc_getAssociatedObject(self, _cmd);
if (number) {
return number.boolValue;
}
self.fd_viewControllerBasedNavigationBarAppearanceEnabled = YES;
return YES;
}
- (void)setFd_viewControllerBasedNavigationBarAppearanceEnabled:(BOOL)enabled
{
SEL key = @selector(fd_viewControllerBasedNavigationBarAppearanceEnabled);
objc_setAssociatedObject(self, key, @(enabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
同时为了适配ViewController里本身有UIScrollView可以左右滚动的情形,避免滚动scrollView的手势与侧滑返回的手势冲突,可以在UIScrollView里重写方法判断
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (self.contentOffset.x <= 0) {
if ([otherGestureRecognizer.delegate isKindOfClass:NSClassFromString(@"_FDFullscreenPopGestureRecognizerDelegate")]) {
return YES;
}
}
return NO;
}
- 方案三
作者:谭真
demo:TestPopGestureSolution3
文章介绍:一行代码,让你的应用中UIScrollView的滑动与侧滑返回并存
GitHub代码:TZScrollViewPopGesture
说明:
添加侧滑只要设置UINavigationController的代理的navigationController: didShowViewController: animated:
方法里设置
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
navigationController.interactivePopGestureRecognizer.delegate = nil;
}
为了设置让包含有scrollView的Controller也支持侧滑pop返回,直接给scrollView添加一个pan手势,处理这个手势的target-action是navgiationController.interactivePopGestureRecognizer.delegate的handleNavigationTransition方法
@implementation UIViewController (TZPopGesture)
- (void)tz_addPopGestureToView:(UIView *)view {
if (!view) return;
if (!self.navigationController) {
// 在控制器转场的时候,self.navigationController可能是nil,这里用GCD和递归来处理这种情况
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self tz_addPopGestureToView:view];
});
} else {
UIPanGestureRecognizer *pan = self.tz_popGestureRecognizer;
if (![view.gestureRecognizers containsObject:pan]) {
[view addGestureRecognizer:pan];
}
}
}
- (UIPanGestureRecognizer *)tz_popGestureRecognizer {
UIPanGestureRecognizer *pan = objc_getAssociatedObject(self, _cmd);
if (!pan) {
// 侧滑返回手势 手势触发的时候,让target执行action
id target = self.navigationController.tz_popDelegate;
SEL action = NSSelectorFromString(@"handleNavigationTransition:");
pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:action];
pan.maximumNumberOfTouches = 1;
// 这让nav来处理是否响应侧滑
pan.delegate = self.navigationController;
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
objc_setAssociatedObject(self, _cmd, pan, OBJC_ASSOCIATION_ASSIGN);
}
return pan;
}
同时 pan.delegate = self.navigationController;
对gesture拦截处理,让nav可以对scrollView判断是响应侧滑还是正常的滑动
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
if ([[self valueForKey:@"_isTransitioning"] boolValue]) {
return NO;
}
if ([self.navigationController.transitionCoordinator isAnimated]) {
return NO;
}
if (self.childViewControllers.count <= 1) {
return NO;
}
UIViewController *vc = self.topViewController;
if (vc.tz_interactivePopDisabled) {
return NO;
}
// 侧滑手势触发位置
CGPoint location = [gestureRecognizer locationInView:self.view];
CGPoint offSet = [gestureRecognizer translationInView:gestureRecognizer.view];
BOOL ret = (0 < offSet.x && location.x <= 40);
// NSLog(@"%@ %@",NSStringFromCGPoint(location),NSStringFromCGPoint(offSet));
return ret;
}
/// 只有当系统侧滑手势失败了,才去触发ScrollView的滑动
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
- 方案四
在实际开发中使用过的一种方式一种简便的方式,在ViewController的viewDidLoad
里添加一行代码(最好在base类里加或写一个分类统一加),这种方法简单高效但会面临一些其他问题,参考文章:navigationController侧滑
demo:TestPopGestureSolution4
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.interactivePopGestureRecognizer.delegate = (id)self;
}
其他非主流方案
- 方案五
作者:参考网上想法
demo:TestPopGestureSolution5
实现方式:在UINavigationController里维护一个截图的数组,同时让原生的侧滑返回失效
- (void)loadView{
[super loadView];
[self initilization];
}
- (void)initilization{
self.backImgs = [[NSMutableArray alloc] init];
}
- (void)loadBaseUI{
//原生方法无效
self.interactivePopGestureRecognizer.enabled = NO;
//设置手势
self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognizerAction:)];
[self.view addGestureRecognizer:self.panGestureRecognizer];
}
拦截push方法,让push时设置一张截图让到数组里
#pragma mark- public method
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
//截图
UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, 1.0);
[[UIApplication sharedApplication].keyWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.backImgs addObject:img];
[super pushViewController:viewController animated:animated];
}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated{
[_backImgs removeLastObject];
return [super popViewControllerAnimated:animated];
}
在侧滑时,对手势的移动条件及距离进行修改适配
- 只有在滚动的offset.x为0-40之间才处理手势
- 让滑动刚开始时,将上一级的Controller的截图显示出来插入superView里显示,好让有侧滑比较效果
3、在滚动中时,将当前navigationController的View的Frame移动位置,同时设置上一级页面的截图的alpha值,让有一个渐变的效果
4、手势结束是,判断当前手势所处位置,如果超过50,这自动无动画pop,然后删除remove背景截图,同时让navigationcontroller的frame的x为0,完整展示之前的Controller
#pragma mark- private method
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
if ([[self valueForKey:@"_isTransitioning"] boolValue]) {
return NO;
}
if ([self.navigationController.transitionCoordinator isAnimated]) {
return NO;
}
if (self.childViewControllers.count <= 1) {
return NO;
}
//UIViewController *vc = self.topViewController;
// 侧滑手势触发位置
CGPoint location = [gestureRecognizer locationInView:self.view];
CGPoint offSet = [gestureRecognizer translationInView:gestureRecognizer.view];
BOOL ret = (0 < offSet.x && location.x <= 40);
// NSLog(@"%@ %@",NSStringFromCGPoint(location),NSStringFromCGPoint(offSet));
return ret;
}
- (void)panGestureRecognizerAction:(UIPanGestureRecognizer*)panGestureRecognizer{
if ([self.viewControllers count] == 1) {
return ;
}
if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) {
NSLog(@"滑动开始");
//存放滑动开始的位置
self.panBeginPoint = [panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow];
//插入图片
[self insertLastViewFromSuperView:self.view.superview];
}else if(panGestureRecognizer.state == UIGestureRecognizerStateEnded){
NSLog(@"滑动结束");
//存放数据
self.panEndPoint = [panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow];
if ((_panEndPoint.x - _panBeginPoint.x) > 50) {
[UIView animateWithDuration:0.3 animations:^{
[self moveNavigationViewWithLenght:[UIScreen mainScreen].bounds.size.width];
} completion:^(BOOL finished) {
[self removeLastViewFromSuperView];
[self moveNavigationViewWithLenght:0];
[self popViewControllerAnimated:NO];
}];
}else{
[UIView animateWithDuration:0.3 animations:^{
[self moveNavigationViewWithLenght:0];
}];
}
}else{
//添加移动效果
CGFloat panLength = ([panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow].x - _panBeginPoint.x);
if (panLength > 0) {
[self moveNavigationViewWithLenght:panLength];
}
}
}
/**
* 移动视图界面
*
* @param lenght 移动的长度
*/
- (void)moveNavigationViewWithLenght:(CGFloat)lenght{
//图片位置设置
self.view.frame = CGRectMake(lenght, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
//图片动态阴影
_backView.alpha = (lenght/[UIScreen mainScreen].bounds.size.width)*2/3 + 0.33;
}
/**
* 插图上一级图片
*
* @param superView 图片的superView
*/
- (void)insertLastViewFromSuperView:(UIView *)superView{
//插入上一级视图背景
if (_backView == nil) {
_backView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
_backView.image = [_backImgs lastObject];;
}
[self.view.superview insertSubview:_backView belowSubview:self.view];
}
/**
* 移除上一级图片
*/
- (void)removeLastViewFromSuperView{
[_backView removeFromSuperview];
_backView = nil;
}
- 方案六(个人觉得最佳方案)
使用FDFullscreenPopGesture+TZScrollViewPopGesture结合的方式有效解决一般从noNavBar->noNavBar,noNavBar->hasNavBar会有跳动的感觉
demo:TestPopGestureSolution6
小结
方案一和方案二使用自定义对navigationController.interactivePopGestureRecognizer.delegate进行替换处理
方案三和方案四是继续使用系统的interactivePopGestureRecognizer.delegate
同时方案二和方案四都处理了scrollView的侧滑返回问题,但由于方案二处理scrollView侧滑时使用继承重写,在有些使用第三方时并不很方便,这一点,方案四一句代码就处理了很方便,就整体代码而言,感觉方案四最优,但方案二还能自动处理有无导航栏的处理,方案四没有涉及这一块儿,但方案四和方案二是可以混用的,方案二+方案四感觉是挺不错的选择
在上面列出的几种解决方案中,只有FDFullscreenPopGesture很好的处理有没有隐藏导航栏的各个页面的切换导致navigationbar闪一下的问题,但在处理scrollView相关的侧滑时使用的方式不是很优雅,而且对于一些不能重新定义一个scrollView子类的页面没法很好的适配,而TZScrollViewPopGesture则很好的处理了这个问题,但TZScrollViewPopGesture在处理导航栏是否隐藏跳转时有点儿跳转的突兀,所以这2个合起来是最好的一种处理方式。
全部例子demo NavPOPGestureBack