首先, 起因就是被要求为一个已经开发并上线的项目添加返回手势, 因为本身并不熟悉项目, 所有必须使用无侵入性的方法去实现, 实现的方案也是千千万, 只是说明一下我所使用的方法, 自认为超级简洁和方便。
1.runtime添加手势给UIViewcontroller
最先想到的就是利用runtime添加手势给UIViewcontroller, 而且系统自带侧滑手势的回调方法handleNavigationTransition:,我们在自己的手势上直接用它的回调方法, 大大减少了我们的代码量和复杂度。
#import "UIViewController+popGesture.h"
@implementation UIViewController (popGesture)
+ (void)load{
[super load];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 假如要打开controller的统计 ,则把下面这行代码打开
__gbh_tracer_swizzleMethod([self class], @selector(loadView), @selector(newLoadView));
});
}
- (void)newLoadView {
[self newLoadView];
id target = self.navigationController.interactivePopGestureRecognizer.delegate;
// handleNavigationTransition:为系统私有API,即系统自带侧滑手势的回调方法,我们在自己的手势上直接用它的回调方法
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
panGesture.delegate = self; // 设置手势代理,拦截手势触发
[self.view addGestureRecognizer:panGesture];
// 一定要禁止系统自带的滑动手势
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
// 什么时候调用,每次触发手势之前都会询问下代理方法,是否触发
// 作用:拦截手势触发
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// 当前控制器是根控制器时,不可以侧滑返回,所以不能使其触发手势
if(self.navigationController.childViewControllers.count == 1)
{
return NO;
}
return YES;
}
//// 允许多个手势并发
//- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
// return YES;
//}
// 交换方法
void __gbh_tracer_swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector){
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
@end
这样就实现了界面返回,是不是很简单,不过这样只能实现UIViewController界面的返回,在拥有UITableView和UIScrollview时就失效了,这是为什么呢?
因为我们的返回代码是加载在UIViewController上,并没有为UIScrollview添加,返回的手势并不能传递到UIViewController,所以就失效了
2.处理滚动视图手势问题
为了无侵入依然使用分类的方法,依然我们已经分析到原因,只需要滚动视图将我们需要的返回手势传递下去即可
#import "UIScrollView+popGesture.h"
@implementation UIScrollView (popGesture)
#define IPHONE_H [UIScreen mainScreen].bounds.size.height //屏幕的高度
#define IPHONE_W [UIScreen mainScreen].bounds.size.width // 屏幕的宽度
// 手势事件会一直往下传递,不论当前层次是否对该事件进行响应。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([self panBack:gestureRecognizer]) {
return YES;
}
return NO;
}
//location_X可自己定义,其代表的是滑动返回距左边的有效长度
- (BOOL)panBack:(UIGestureRecognizer *)gestureRecognizer {
//是滑动返回距左边的有效长度 左1/8有效区域
int location_X = 0.125 * IPHONE_W;
if (gestureRecognizer == self.panGestureRecognizer) {
UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint point = [pan velocityInView:pan.view];
UIGestureRecognizerState state = gestureRecognizer.state;
if (UIGestureRecognizerStateBegan == state || UIGestureRecognizerStatePossible == state) {
CGPoint location = [gestureRecognizer locationInView:self];
if (point.x > 0 && location.x < location_X && self.contentOffset.x <= 0) {
return YES;
}
}
}
return NO;
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([self panBack:gestureRecognizer]) {
return NO;
}
return YES;
}
这样任何滚动视图都实现了滑动返回,是不是很简单,虽然不会写作,但是都是干货,觉得有用就给我个赞吧,你的赞就是我的动力。