彩票10——滑动移除控制器全屏实现
一、图示
二、分析
原本系统有滑动删除的,但是我们添加了放回按钮以后没有了,那么这下就尴尬了吧。那么我们就行来实现一下。
其实我们只需要把 系统手势的代理设置为nil 就可以实现这样的功能了,但是这用实现,我们是能滑动左边的并且不包含导航条。并且会产生一个bug,就是如果我们在根控制器上滑动了,那么我们就 push 不了其他控制器了。那么怎么解决呢,其实解决方式很简单,我们一开始记住我们的代理,然后在 did 控制器的时候,我们判断一下,当前的控制器是不是根控制器,如果是还原,不是赋值为nil。
另外的处理方式,就是我们自己添加一个滑动手势,然后我们使用系统的处理方法和targer来处理这个手势就行了。
三、非全屏滑动删除的处理方式
这种方式处理的结果就是只能从左侧滑动时删除。
这种方式需要添加 UINavigationControllerDelegate 代理
//
// QWMNavigationController.m
// 03_UIView79_彩票
//
// Created by 杞文明 on 17/8/13.
// Copyright © 2017年 杞文明. All rights reserved.
//
#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate>
/** 系统手势代理 */
@property (nonatomic, strong) id popGesture;
@end
@implementation QWMNavigationController
········
-(void)viewDidLoad{
[super viewDidLoad];
self.popGesture = self.interactivePopGestureRecognizer.delegate;
self.delegate = self;
}
// 解决如果在根控制器上滑动了,不能删除的情况
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
if(self.viewControllers[0]==viewController){//根控制器
self.interactivePopGestureRecognizer.delegate = self.popGesture;
}else{
// 清空手势代理就能实现滑动返回, iOS6不支持
self.interactivePopGestureRecognizer.delegate = nil;
}
}
·····
@end
四、全屏滑动删除的处理方式 1 —— KVC
这种方式的处理就是,自己添加一个滑动手势 UIPanGestureRecognizer 这个手势的 target 和 action,使用系统手势使用的。
那么我们使用
NSLog(@"%@",self.interactivePopGestureRecognizer);
打印一下系统手势的信息
如下
<UIScreenEdgePanGestureRecognizer: 0x7fd258d1ab20;
state = Possible;
delaysTouchesBegan = YES;
view = <UILayoutContainerView 0x7fd258d198a0>;
target= <
(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fd258e1be20>)
>
>
通过上面的信息,我们可以知道 我们 添加的手势的 action 就是 handleNavigationTransition:
方法。
但是我们 target 我们还没办法拿到。
我们使用 oc 中的 runtime 机制,来获取我们的属性名称,然后使用 KVC 来获取我们的 target
我们使用 runtime 机制打印出 UIGestureRecognizer 里面的属性
// oc runtime 机制 只能动态获取当前类的成员属性,不能获取其子类,或者父类的属性
// __unsafe_unretained Class 要获取哪个类的成员属性
// unsigned int *outCount 获取Class 下面的所有成员属性的个数
unsigned int outCount;
Ivar * ivars = class_copyIvarList([UIGestureRecognizer class], &outCount);
for (int i=0; i<outCount; i++) {
NSString * name = @(ivar_getName(ivars[i]));
NSLog(@"%@",name);
}
打印结果
2017-08-26 16:21:36.885 03_UIView79_彩票[12961:57679] _gestureFlags
2017-08-26 16:21:36.885 03_UIView79_彩票[12961:57679] _targets
2017-08-26 16:21:36.885 03_UIView79_彩票[12961:57679] _delayedTouches
2017-08-26 16:21:36.886 03_UIView79_彩票[12961:57679] _delayedPresses
2017-08-26 16:21:36.886 03_UIView79_彩票[12961:57679] _view
2017-08-26 16:21:36.886 03_UIView79_彩票[12961:57679] _lastTouchTimestamp
2017-08-26 16:21:36.887 03_UIView79_彩票[12961:57679] _state
2017-08-26 16:21:36.887 03_UIView79_彩票[12961:57679] _allowedTouchTypes
2017-08-26 16:21:36.887 03_UIView79_彩票[12961:57679] _initialTouchType
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _internalActiveTouches
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _forceClassifier
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _requiredPreviewForceState
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _touchForceObservable
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _touchForceObservableAndClassifierObservation
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _forceTargets
2017-08-26 16:21:36.888 03_UIView79_彩票[12961:57679] _forcePressCount
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _beganObservable
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _failureRequirements
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _failureDependents
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _delegate
2017-08-26 16:21:36.889 03_UIView79_彩票[12961:57679] _allowedPressTypes
2017-08-26 16:21:36.890 03_UIView79_彩票[12961:57679] _gestureEnvironment
我们可以看到有一个 —targets 属性,然后我们 通过 KVC 获取这个值,然后打印一下。
UIScreenEdgePanGestureRecognizer * gest = self.interactivePopGestureRecognizer;
id targets = [gest valueForKeyPath:@"_targets"];
NSLog(@"%@",targets);
结果
(
"(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fb3c9d0b5d0>)"
)
我们可以看到 这是一个数组,但是我们还是没法知道我么的 target。
我们调试一下看一下。我们会发现原来属性叫 _target
现在我们已经知道属性名了,那么我么既可以通过 KVC 来获取了
// 通过 KVC 方式获取 _target
id target = [targets[0] valueForKeyPath:@"_target"];
完整如下
//
// QWMNavigationController.m
// 03_UIView79_彩票
//
// Created by 杞文明 on 17/8/13.
// Copyright © 2017年 杞文明. All rights reserved.
//
#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate>
/** 系统手势代理 */
@property (nonatomic, strong) id popGesture;
@end
@implementation QWMNavigationController
.......
-(void)viewDidLoad{
[super viewDidLoad];
UIScreenEdgePanGestureRecognizer * gest = self.interactivePopGestureRecognizer;
//KVC获取 _targets
NSArray * targets = [gest valueForKeyPath:@"_targets"];
// 通过 KVC 方式获取 _target
id target = [targets[0] valueForKeyPath:@"_target"];
//添加滑动手势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:target action:@selector(handleNavigationTransition:)];
[self.view addGestureRecognizer:pan];
}
@end
.......
五、全屏滑动删除的处理方式 2 ——delegate
这种处理方式,其实有原因的,我们在创建一个手势的时候,我们发现,我们添加的 target 和 delegate 是一样的,那么系统的应该也是一样的。
如
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
pan.delegate = self;
所以需要的 target 其实就是delegate 。
id target = self.interactivePopGestureRecognizer.delegate;
但是如果我们这个添加了 会出现上面我们出现过的bug : 就是如果我们在根控制器上滑动了,那么我们就 push 不了其他控制器了.
那么怎么解决呢?
我们可以添加 UIGestureRecognizerDelegate 代理。手指开始时去判断是不是根控制器,如果是的话,那么我们禁止手势,如果不是我们响应手势
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
return self.viewControllers.count > 1;
}
完整代码如下
//
// QWMNavigationController.m
// 03_UIView79_彩票
//
// Created by 杞文明 on 17/8/13.
// Copyright © 2017年 杞文明. All rights reserved.
//
#import "QWMNavigationController.h"
#import <objc/runtime.h>
@interface QWMNavigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate>
/** 系统手势代理 */
@property (nonatomic, strong) id popGesture;
@end
@implementation QWMNavigationController
-(void)viewDidLoad{
[super viewDidLoad];
id target = self.interactivePopGestureRecognizer.delegate;
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:target action:@selector(handleNavigationTransition:)];
[self.view addGestureRecognizer:pan];
pan.delegate = self;
}
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
return self.viewControllers.count > 1;
}
@end