来自  资质荣誉 2019-09-23 06:31 的文章
当前位置: 澳门太阳娱乐手机登录 > 资质荣誉 > 正文

简单的讲的抽屉效果,的落到实处思路

简单的抽屉效果是由3 个View 组成,顶层默认显示的mainV,左边的leftV以及右边的rightV ,当mainV 监听到滑动时,计算滑动的偏移量,控制显示leftV或者rightV.

导航控制器默认自带了侧滑pop掉当前控制器的功能,但是只有在界面的左边拖动的时候才会触发侧滑POP的功能,也就是说手势触发的范围只能在左边的一小块,说明系统手势触发的方法实现了滑动返回功能。

废话不多说,上代码.

我们创建手势对象的时候,需要绑定监听者

一:所以,首先我们需要在头文件中定义三个View的属性,来给外界调用,实现设置对应的属性和效果:

UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector];
1 @property (nonatomic, weak, readonly) UIView *mainV;2 3 @property (nonatomic, weak, readonly) UIView *leftV;4 5 @property (nonatomic, weak, readonly) UIView *rightV;

当用户在界面左边滑动,有滑动返回功能,这是因为触发手势了,调用target的action方法,说明方法内部实现滑动返回功能,否则就不会有滑动返回效果。在导航控制器的ViewDidLoad方法中打印滑动手势

二:然后在实现文件中定义对应的宏,后面要用到:

- viewDidLoad { [super viewDidLoad]; NSLog(@"%@",self.interactivePopGestureRecognizer); NSLog(@"%@",self.interactivePopGestureRecognizer.delegate); }

澳门太阳娱乐在线网址 1

打印结果如下

 1 // @"frame" 2 //自动提示宏  3 #define XMGkeyPath(objc, keyPath) @objc.keyPath, #keyPath)) 4  5 // 在宏里面如果在参数前添加了#,就会把参数变成C语言字符串 6  7 // 获取屏幕的宽度 8 #define screenW [UIScreen mainScreen].bounds.size.width 9 10 // 获取屏幕的高度11 #define screenH [UIScreen mainScreen].bounds.size.height
 <UIScreenEdgePanGestureRecognizer: 0x7f87b16a9360; state = Possible; delaysTouchesBegan = YES; view = <UILayoutContainerView 0x7f87b16a7ac0>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7f87b16aeb70>)>>

self.interactivePopGestureRecognizer.delegate =<_UINavigationInteractiveTransition: 0x7faf4a4356f0>

澳门太阳娱乐在线网址 2

可以看出:系统自带的手势是UIScreenEdgePanGestureRecognizer类型的对象 看名称就知道,这个手势的范围只能在屏幕的边缘系统自带的手势的target 是_UINavigationInteractiveTransition类型的对象系统调用的方法是handleNavigationTransition:系统UIScreenEdgePanGestureRecognizer手势的代理就是_UINavigationInteractiveTransition

宏入门:宏定义的黑魔法 - 宏菜鸟起飞手册

那么如何给自己的导航控制器添加1个全屏幕的滑动手势呢:这里仅仅是提供一种思路 使用截图的方式来实现全屏滑动返回

三:在ViewDidLoad中调用下面这个方法实现三个View的创建:

为了方便演示 在工程中创建了1个有三个自控制器的导航控制器

澳门太阳娱乐在线网址 3

澳门太阳娱乐在线网址 4basic.gif

 1 // 添加所有的子控件 2 - setUpAllChildView 3 { 4     // left 5     UIView *leftV = [[UIView alloc] initWithFrame:self.view.bounds]; 6     leftV.backgroundColor = [UIColor greenColor]; 7     [self.view addSubview:leftV]; 8     _leftV = leftV; 9     10     // right11     UIView *rightV = [[UIView alloc] initWithFrame:self.view.bounds];12     rightV.backgroundColor = [UIColor blueColor];13     [self.view addSubview:rightV];14     _rightV = rightV;15     16     // main17     UIView *mainV = [[UIView alloc] initWithFrame:self.view.bounds];18     mainV.backgroundColor = [UIColor redColor];19     [self.view addSubview:mainV];20     _mainV = mainV;21 }

在导航控制器的.h文件中定义了一些宏

澳门太阳娱乐在线网址 5

#import "GZDNavgationController.h"#define kAnimatationDuration 0.25#define kScreenWidth [UIScreen mainScreen].bounds.size.width#define kScreenHeight [UIScreen mainScreen].bounds.size.height#define kScreenSize [UIScreen mainScreen].bounds.size#define kScreenBounds [UIScreen mainScreen].bounds

四:在ViewDidLoad中为mainV界面添加滑动手势:

声明了三个属性

 1     // 添加拖拽手势 2     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector]; 3      4     [_mainV addGestureRecognizer:pan]; 5 
@interface GZDNavgationController ()//装有所有截图的数组@property (strong,nonatomic) NSMutableArray *screenImages;//最后1个截图图片的imageView@property (strong,nonatomic) UIImageView *lastImageView;//遮罩@property (strong,nonatomic) UIView *coverView;@end

使用KVO监听frame的变化:

首先进行懒加载

澳门太阳娱乐在线网址 6

-(NSMutableArray *)screenImages { if (!_screenImages) { _screenImages = [NSMutableArray array]; } return _screenImages; }//为了保证不创建太多的imageview,所以使用懒加载的方式- (UIImageView *)lastImageView{ if (!_lastImageView) { _lastImageView = [[UIImageView alloc] init]; } return _lastImageView;}//遮罩的view- coverView{ if (!_coverView) { _coverView = [[UIView alloc] init]; _coverView.backgroundColor = [UIColor blackColor]; _coverView.alpha = 0.5; _coverView.frame = kScreenBounds; } return _coverView;}
1     2     // KVO作用:时刻监听某个对象的某个属性的改变3     // _main frame属性的改变4     // Observer:观察者5     // KeyPath:监听的属性6     // NSKeyValueObservingOptionNew:表示监听新值的改变7     [_mainV addObserver:self forKeyPath:XMGkeyPath(_mainV, frame) options:NSKeyValueObservingOptionNew context:nil];8     

在viewDidLoad 方法中创建平移手势

澳门太阳娱乐在线网址 7

- viewDidLoad { [super viewDidLoad]; //创建平移手势 UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; //将平移手势添加到导航控制器上 [self.view addGestureRecognizer:panGesture]; }

五:实现滑动手势的方法,和监听属性变化的方法:

写了1个方法用来截取控制器全屏的图片

澳门太阳娱乐在线网址 8

- getScreenImage{ //截取上一个控制器的全屏的图片 //开启上下文 UIGraphicsBeginImageContextWithOptions(kScreenSize, YES, 0.0); //将self.View渲染到图形上下文 [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; //从图形上下文中获得图片 UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext(); //关闭图形上下文 UIGraphicsEndImageContext(); [self.screenImages addObject:screenShot]; }
 1 #define targetR 300 2  3 #define targetL -200 4  5 - pan:(UIPanGestureRecognizer *)pan 6 { 7     // 获取手势的偏移量 8     CGPoint transP = [pan translationInView:_mainV]; 9     // 获取x轴的偏移量,相对于上一次10     CGFloat offsetX = transP.x;11     // 修改最新的main.frame,12     _mainV.frame = [self frameWithOffsetX:offsetX];13     // 复位14     [pan setTranslation:CGPointZero inView:_mainV];15     // 判断下当前手指有没有抬起,表示手势结束16     if (pan.state == UIGestureRecognizerStateEnded) { // 手指抬起,定位17         // x>屏幕的一半,定位到右边某个位置18         CGFloat target = 0;19         if (_mainV.frame.origin.x > screenW * 0.5) {20             target = targetR;21         }else if (CGRectGetMaxX(_mainV.frame) < screenW * 0.5){22             // 最大的x < 屏幕一半的时候,定义到左边某个位置23             target = targetL;24         }25         // 获取x轴的偏移量26         CGFloat offsetX = target - _mainV.frame.origin.x;27         [UIView animateWithDuration:0.25 animations:^{28             _mainV.frame = [self frameWithOffsetX:offsetX];29         }];30     }31 }32 33 #define XMGMaxY 10034 35 // 给定一个x轴的偏移量计算下最新main的frame36 - frameWithOffsetX:offsetX37 {38     39     41     42     // 获取当前main的frame43     CGRect frame = _mainV.frame;44     45     // 计算当前的x,y,w,h46     // 获取最新的x47     CGFloat x = frame.origin.x + offsetX;48     49     // 获取最新的y50     CGFloat y = x / screenW * XMGMaxY;51     52     // 当用户往左边移动的时候,_main.x < 0,y需要增加,为正53     if (frame.origin.x < 0) {54         y = -y;55     }56     // 获取最新的h57     CGFloat h = screenH - 2 * y;58     // 获取缩放比例59     CGFloat scale = h / screenH;60     // 获取最新的w61     CGFloat w = screenW * scale;62     return CGRectMake(x, y, w, h);63 }

由于第一张绿色控制器的的图片要在控制器显示的时候就截图下来,所以考虑在viewDidAppear 中截图添加到数组中

澳门太阳娱乐在线网址 9

- viewDidAppear:animated{ [super viewDidAppear:animated]; //因为导航控制器有可能会消失,出现多次 //第一张图片只在数组没有元素的时候才截取,如果截图数组中有图片就不截取 if (self.screenImages.count > 0)return; [self getScreenImage]; }

监听属性的变化:

处理平移手势的方法

澳门太阳娱乐在线网址 10

- handlePanGesture:(UIPanGestureRecognizer *)pan{ //如果子控制器的个数小于等于1-->就是导航控制器里面只有根控制器在,此时是不需要手势,直接返回 if (self.viewControllers.count <= 1)return; //手指在屏幕上水平方向移动的距离 CGFloat moveX = [pan translationInView:self.view].x;//如果手指向左移动此时moveX <0 ,无需判断左移的情况 所以直接返回. if (moveX < 0)return;//能来到下面 说明满足手势触发的条件 即不是导航控制器的根控制器 同时手势是向右边滑动 //改变导航控制器的view的transform,使整个控制器都能够向左移动 self.view.transform = CGAffineTransformMakeTranslation; //将导航控制器的view平移操作之后下面是没有任何东西的,所以会显示为黑色.//考虑将截图的view 添加到window 上面 //获取window对象 UIWindow *window = [UIApplication sharedApplication].keyWindow; //取出数组中的最后1个image将其加载到懒加载的imageView中 self.lastImageView.image = self.screenImages[self.screenImages.count - 2];//设置frame self.lastImageView.frame = kScreenBounds; //在window上插入这个view [window insertSubview:self.lastImageView atIndex:0]; //添加遮罩view 将遮罩的view 插入到lastImageView 的上面 [window insertSubview:self.coverView aboveSubview:self .lastImageView]; //拿到self的view 的x CGFloat x = self.view.frame.origin.x; //如果手势的状态是停止的时候 //判断最终的停靠位置 if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) { //如果平移的距离比屏幕宽度的一半还要大 if (x >= kScreenWidth * 0.5){ [UIView animateWithDuration:kAnimatationDuration animations:^{ self.view.transform = CGAffineTransformMakeTranslation(kScreenWidth, 0); }completion:^(BOOL finished) { //完成平移之后控制器出栈 [self popViewControllerAnimated:NO]; //导航控制器的view 被移动到最右边去了 self.view.transform = CGAffineTransformIdentity; }]; }else{//如果平移的距离比屏幕宽度的一半要小 [UIView animateWithDuration:kAnimatationDuration animations:^{ //还原控制器 self.view.transform = CGAffineTransformIdentity; }]; } } }
1 // 只要监听的属性一改变,就会调用2 - observeValueForKeyPath:(NSString *)keyPath ofObject:object change:(NSDictionary *)change context:context3 {4     if (_mainV.frame.origin.x > 0) { // 往右滑动,显示左边控件,隐藏右边控件5         _rightV.hidden = YES;6     }else if (_mainV.frame.origin.x < 0){ // 往左滑动,显示右边控件7         _rightV.hidden = NO;8     }9 }

重写两个方法 拦截push 和pop的操作

澳门太阳娱乐在线网址 11

//拦截push操作的方法 在这个方法里面截图- pushViewController:(UIViewController *)viewController animated:animated{ //在调用super使控制器入栈之后 [super pushViewController:viewController animated:animated];//截图 [self getScreenImage];}//拦截pop操作的方法- (UIViewController *)popViewControllerAnimated:animated{//移除图片 [self.lastImageView removeFromSuperview];//移除遮罩 [self.coverView removeFromSuperview];//移除截图数组中的最后1个元素 [self.screenImages removeLastObject];//调用父类pop方法出栈 return [super popViewControllerAnimated:animated];}

注意:KVO使用结束后一定要移除观察者

最后实现的效果

1 // 注意:当对象被销毁的时候,一定要注意移除观察者2 - dealloc3 {4     // 移除观察者5     [_mainV removeObserver:self forKeyPath:XMGkeyPath(_mainV, frame)];6 }

澳门太阳娱乐在线网址 12澳门太阳娱乐在线网址,完成.gif

六:为界面添加一个单击手势,实现单击屏幕还原

可以看到在滑动栈顶控制器的时候 其实显示在下面的是1个全屏幕的截图而已...

1      // 给控制器的view添加一个点按2      3      UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector];4     5      [self.view addGestureRecognizer:tap];

还原方法的实现:

澳门太阳娱乐在线网址 13

 1 - tap 2 { 3     if (_mainV.frame.origin.x != 0) { 4         // 把_mainV还原最开始的位置 5          6         [UIView animateWithDuration:0.25 animations:^{ 7             _mainV.frame = self.view.bounds; 8              9         }];10         11     }12 }

澳门太阳娱乐在线网址 14

下面就是最终的效果:

 

澳门太阳娱乐在线网址 15

澳门太阳娱乐在线网址 16

澳门太阳娱乐在线网址 17

澳门太阳娱乐在线网址 18

本文由澳门太阳娱乐手机登录发布于 资质荣誉,转载请注明出处:简单的讲的抽屉效果,的落到实处思路

关键词: