首先, 起因就是被要求為一個已經(jīng)開發(fā)并上線的項目添加返回手勢, 因為本身并不熟悉項目, 所有必須使用無侵入性的方法去實現(xiàn), 實現(xiàn)的方案也是千千萬, 只是說明一下我所使用的方法, 自認為超級簡潔和方便。
1.runtime添加手勢給UIViewcontroller
最先想到的就是利用runtime添加手勢給UIViewcontroller, 而且系統(tǒng)自帶側(cè)滑手勢的回調(diào)方法handleNavigationTransition:,我們在自己的手勢上直接用它的回調(diào)方法, 大大減少了我們的代碼量和復雜度。
#import "UIViewController+popGesture.h"
@implementation UIViewController (popGesture)
+ (void)load{
[super load];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 假如要打開controller的統(tǒng)計 ,則把下面這行代碼打開
__gbh_tracer_swizzleMethod([self class], @selector(loadView), @selector(newLoadView));
});
}
- (void)newLoadView {
[self newLoadView];
id target = self.navigationController.interactivePopGestureRecognizer.delegate;
// handleNavigationTransition:為系統(tǒng)私有API,即系統(tǒng)自帶側(cè)滑手勢的回調(diào)方法,我們在自己的手勢上直接用它的回調(diào)方法
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
panGesture.delegate = self; // 設置手勢代理,攔截手勢觸發(fā)
[self.view addGestureRecognizer:panGesture];
// 一定要禁止系統(tǒng)自帶的滑動手勢
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
// 什么時候調(diào)用,每次觸發(fā)手勢之前都會詢問下代理方法,是否觸發(fā)
// 作用:攔截手勢觸發(fā)
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// 當前控制器是根控制器時,不可以側(cè)滑返回,所以不能使其觸發(fā)手勢
if(self.navigationController.childViewControllers.count == 1)
{
return NO;
}
return YES;
}
//// 允許多個手勢并發(fā)
//- (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
這樣就實現(xiàn)了界面返回,是不是很簡單,不過這樣只能實現(xiàn)UIViewController界面的返回,在擁有UITableView和UIScrollview時就失效了,這是為什么呢?
因為我們的返回代碼是加載在UIViewController上,并沒有為UIScrollview添加,返回的手勢并不能傳遞到UIViewController,所以就失效了
2.處理滾動視圖手勢問題
為了無侵入依然使用分類的方法,依然我們已經(jīng)分析到原因,只需要滾動視圖將我們需要的返回手勢傳遞下去即可
#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有效區(qū)域
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;
}
這樣任何滾動視圖都實現(xiàn)了滑動返回,是不是很簡單,雖然不會寫作,但是都是干貨,覺得有用就給我個贊吧,你的贊就是我的動力。