
一擊即中.jpeg
前言:今天好好講解一下導航欄全屏手勢返回,以前只知道拿別人的來用,現在想花點時間了解其中的原理。 今天把自己學習到的分享出來,大家一起學習進步。。。
Pragma mark — NO.1 使用全屏返回的原因與技術背景
1.手機屏幕大了,沒有全屏返回,用戶體驗感下降(雖然很多人也學還不知道大多數應用都有全屏返回功能,還傻傻的去點左上角的返回鍵)
2. 界面要求:
-1 : 要求在下個push出來的控制器中隱藏掉導航欄,那么我們系統(tǒng)自帶的左側邊緣滑動返回也沒有了
-2 : push出來的控制器左上角的返回鍵我們通常需要用按鈕自定義,這種情況下也會覆蓋掉左側邊緣滑動返回
Pragma mark — NO.2 簡單界面搭建
1. 創(chuàng)建個空工程,然后在main storyboard 中給 viewController Embed in 一個navigation controller
2.自己創(chuàng)建一個navigation controller ,與main storyboard 中的關聯(lián)起來
3.創(chuàng)建一個nextViewController ,點擊viewController push 到 nextViewController .
4.在nextViewController 中隱藏 這個 navigationBar
5.點擊nextViewController 的pop按鈕 pop 到 viewController
至此最簡單的項目結構就創(chuàng)建好了(這里我們演示這個push隱藏導航欄的情況)
Pragma mark — NO.3 簡要分析
#我們在自定義的nav中來看:
1.系統(tǒng)nav有這個左側邊緣返回的手勢,說明其應該有一個Pan手勢,并且有這個 target 和 action , 我們直接拿到這個手勢加入到nav.view的手勢中,看能否實現左劃返回
@implementation JJNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addGestureRecognizer:self.interactivePopGestureRecognizer];
}
//self.view:拿到push出來的控制器view
//self.interactivePopGestureRecognizer :系統(tǒng)給我們的導航欄pop返回手勢
//運行工程,我們發(fā)現這樣做是沒有任何反應的
2.第二種思路:拿到系統(tǒng)的self.interactivePopGestureRecognizer手勢中的target和action。 然后我們自己給self.view創(chuàng)建一個Pan(滑動手勢) 將 target 和 action設置為系統(tǒng)的
Pragma mark — NO.4 利用runtime 取得系統(tǒng)手勢的targer屬性
#對于runtime不熟悉的伙伴,可以自行了解一下
#import "JJNavigationController.h"
#import <objc/runtime.h>
@interface JJNavigationController ()
@end
@implementation JJNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
//1.通過運行時,打印手勢中的所有屬性
unsigned int count = 0;
//拷貝所有關于手勢的屬性,包含私有屬性
Ivar *ivars = class_copyIvarList([UIGestureRecognizer class], &count);
//遍歷這個屬性數組,拿到每一個屬性
NSArray *ivarList = [NSArray array];
//初始化一個count那么長的可變數組
NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
for (unsigned int i = 0; i < count; i++) {
//獲取成員變量名
const char *ivarName = ivar_getName(ivars[i]);
//獲取類的成員變量的類型
//const char *ivarType = ivar_getTypeEncoding(ivars[i]);
[mutableList addObject:[NSString stringWithUTF8String:ivarName]];
}
//釋放
free(ivars);
ivarList = [NSArray arrayWithArray:mutableList];
NSLog(@"手勢所有屬性名--%@",ivarList);
}
#打印結果:
Nav全屏手勢返回[1773:90512] 手勢所有屬性名--(
"_gestureFlags",
"_targets",
"_delayedTouches",
"_delayedPresses",
"_view",
"_lastTouchTimestamp",
"_state",
"_allowedTouchTypes",
"_initialTouchType",
"_internalActiveTouches",
"_forceClassifier",
"_requiredPreviewForceState",
"_touchForceObservable",
"_touchForceObservableAndClassifierObservation",
"_forceTargets",
"_forcePressCount",
"_beganObservable",
"_failureRequirements",
"_failureDependents",
"_delegate",
"_allowedPressTypes",
"_gestureEnvironment"
)
Pragma mark — NO.5 通過KVC取得系統(tǒng)手勢的action 和 target
#通過上面的屬性打印,我們可以看出@“_targets”應該是我們想要的
@implementation JJNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *targets = [self.interactivePopGestureRecognizer valueForKey:@"_targets"];
NSLog(@"targets中的東西%@",targets);
}
#打印結果
targets中的東西(
"(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7f9210f0f2c0>)"
)
這樣我們就拿到系統(tǒng)手勢的action和target
Pragma mark — NO.6 創(chuàng)建Pan手勢添加target和action
#獲得系統(tǒng)的target 和 action
NSArray *targets = [self.interactivePopGestureRecognizer valueForKey:@"_targets"];
// NSLog(@"targets中的東西%@",targets);
id target = [targets.firstObject valueForKey:@"target"];
SEL action = NSSelectorFromString(@"handleNavigationTransition:");
#創(chuàng)建Pan手勢
//創(chuàng)建滑動手勢
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:target action:action];
[self.view addGestureRecognizer:panGesture];
#再次運行工程,我們會發(fā)現就已經可全屏pop返回了
- 疑問:我們在nextViewController中沒有處理過任何手勢相關的東西,為什么我們拖動nextViewController的view,會有拖動手勢?
- 解惑:這其中涉及到一個響應者鏈問題。因為我們的nextViewController的view實際上是加在它的父控件,nav.view上的。 所以我們拖動next.view會有手勢。
完整項目地址: nav全屏返回