前言:今天好好讲解一下导航栏全屏手势返回,以前只知道拿别人的来用,现在想花点时间了解其中的原理。 今天把自己学习到的分享出来,大家一起学习进步。。。
Pragma mark — NO.1 使用全屏返回的原因与技术背景
1.手机屏幕大了,没有全屏返回,用户体验感下降(虽然很多人也学还不知道大多数应用都有全屏返回功能,还傻傻的去点左上角的返回键)
2. 界面要求:
-1 : 要求在下个push出来的控制器中隐藏掉导航栏,那么我们系统自带的左侧边缘滑动返回也没有了
-2 : push出来的控制器左上角的返回键我们通常需要用按钮自定义,这种情况下也会覆盖掉左侧边缘滑动返回
Pragma mark — NO.2 简单界面搭建
1. 创建个空工程,然后在main storyboard 中给 viewController Embed in 一个navigation controller
2.自己创建一个navigation controller ,与main storyboard 中的关联起来
3.创建一个nextViewController ,点击viewController push 到 nextViewController .
4.在nextViewController 中隐藏 这个 navigationBar
5.点击nextViewController 的pop按钮 pop 到 viewController
至此最简单的项目结构就创建好了(这里我们演示这个push隐藏导航栏的情况)
Pragma mark — NO.3 简要分析
#我们在自定义的nav中来看:
1.系统nav有这个左侧边缘返回的手势,说明其应该有一个Pan手势,并且有这个 target 和 action , 我们直接拿到这个手势加入到nav.view的手势中,看能否实现左划返回
@implementation JJNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addGestureRecognizer:self.interactivePopGestureRecognizer];
}
//self.view:拿到push出来的控制器view
//self.interactivePopGestureRecognizer :系统给我们的导航栏pop返回手势
//运行工程,我们发现这样做是没有任何反应的
2.第二种思路:拿到系统的self.interactivePopGestureRecognizer手势中的target和action。 然后我们自己给self.view创建一个Pan(滑动手势) 将 target 和 action设置为系统的
Pragma mark — NO.4 利用runtime 取得系统手势的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取得系统手势的action 和 target
#通过上面的属性打印,我们可以看出@“_targets”应该是我们想要的
@implementation JJNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *targets = [self.interactivePopGestureRecognizer valueForKey:@"_targets"];
NSLog(@"targets中的东西%@",targets);
}
#打印结果
targets中的东西(
"(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7f9210f0f2c0>)"
)
这样我们就拿到系统手势的action和target
Pragma mark — NO.6 创建Pan手势添加target和action
#获得系统的target 和 action
NSArray *targets = [self.interactivePopGestureRecognizer valueForKey:@"_targets"];
// NSLog(@"targets中的东西%@",targets);
id target = [targets.firstObject valueForKey:@"target"];
SEL action = NSSelectorFromString(@"handleNavigationTransition:");
#创建Pan手势
//创建滑动手势
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:target action:action];
[self.view addGestureRecognizer:panGesture];
#再次运行工程,我们会发现就已经可全屏pop返回了
- 疑问:我们在nextViewController中没有处理过任何手势相关的东西,为什么我们拖动nextViewController的view,会有拖动手势?
- 解惑:这其中涉及到一个响应者链问题。因为我们的nextViewController的view实际上是加在它的父控件,nav.view上的。 所以我们拖动next.view会有手势。
完整项目地址: nav全屏返回
网友评论