#import "DragerViewController.h"#define screenW [UIScreen mainScreen].bounds.size.width@interface DragerViewController ()/** <#注释#> */@property (nonatomic, weak) UIView *leftV;@property (nonatomic, weak) UIView *rightV;@property (nonatomic, weak) UIView *mainV;@end@implementation DragerViewController- (void)viewDidLoad { [super viewDidLoad]; //1:添加子控件 [self setUp]; //2:添加拖拽平移手势 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; [self.mainV addGestureRecognizer:pan]; //3:给控制器的View添加点按手势:给控制器添加手势,无论点击的是上部的view还是底部的view,控制器都会去响应事件。 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)]; [self.view addGestureRecognizer:tap];}#pragma mark -- tap轻击事件,让抽屉复位- (void)tap{ //让MainV复位 [UIView animateWithDuration:0.5 animations:^{ self.mainV.frame = self.view.bounds; }];}#pragma mark -- 拖拽平移手势事件/** * 1:像是#define 和 static等都可以在@implementation之上定义,或是之下定义均可以 */#define targetR 275#define targetL -275- (void)pan:(UIPanGestureRecognizer *)pan{ /** 1:为什么不使用transform,是因为我们还要去修改高度,使用transform,只能修改,x,y,累加形变(y方向不需要平移) self.mainV.transform = CGAffineTransformTranslate(self.mainV.transform, transP.x, 0); 2:修改控件的frame:1:可以用frame去修改 2:可以利用transform去修改,旋转,平移,缩放,累加形变和非累加形变,清空形变,类型为CGAffineTransform类型 3:将修改frame的方法封装起来,外界传一个x值,返回一个修改后的frame的值。 * */ //1:获取偏移量 CGPoint transP = [pan translationInView:self.mainV]; self.mainV.frame = [self frameWithOffsetX:transP.x]; /** *1:通过x值判断是向左平移还是向右平移:大于0向右平移,小于0向左平移。通过显示和隐藏来控制左右到底显示哪个view 2:view添加的顺序,mainView在最上层,均添加到了self.view上 * */ //2:判断拖动的方向,显示不同的view if(self.mainV.frame.origin.x > 0){ //向右 self.rightV.hidden = YES; }else if(self.mainV.frame.origin.x < 0){ //向左 self.rightV.hidden = NO; } //3:当手指松开时,做自动定位. CGFloat target = 0; if (pan.state == UIGestureRecognizerStateEnded) { if (self.mainV.frame.origin.x > screenW * 0.5 ) { //1判断在右侧 //当前View的x有没有大于屏幕宽度的一半,大于就是在右侧 target = targetR; }else if(CGRectGetMaxX(self.mainV.frame) < screenW * 0.5){ //2.判断在左侧 //当前View的最大的x有没有小于屏幕宽度的一半,小于就是在左侧 target = targetL; } //计算当前mainV的frame. CGFloat offset = target - self.mainV.frame.origin.x; [UIView animateWithDuration:0.5 animations:^{ self.mainV.frame = [self frameWithOffsetX:offset]; }]; } //4:复位:进行复位操作的目的是:让其根据上一次的平移进行平移而不是每次都根据初始位置进行平移 [pan setTranslation:CGPointZero inView:self.mainV]; }#define maxY 100#pragma mark --根据偏移量计算MainV的frame- (CGRect)frameWithOffsetX:(CGFloat)offsetX { //当进行拖拽平移的时候,更改mainView的的x值和高度 /** * 1:x值是累加形变的,所以是frame.origin.x += offsetX 2:求最大y值,设最大的y值为100,用当前的x值乘以最大y值与屏幕的宽度比 3:求拖拽平移的高度:屏幕高度 - 2倍的最大的y值,并返回frame 4:fabs:对计算结果取绝对值,因为当向左滑动的时候,x值为负数 */ //1:x值 CGRect frame = self.mainV.frame; frame.origin.x += offsetX; //当拖动的View的x值等于屏幕宽度时,maxY为最大,最大为100 // 375 * 100 / 375 = 100 //对计算的结果取绝对值 CGFloat y = fabs( frame.origin.x * maxY / screenW); frame.origin.y = y; //2:屏幕的高度减去两倍的Y值 frame.size.height = [UIScreen mainScreen].bounds.size.height - (2 * frame.origin.y); return frame;}/** * 添加view:此时的view以属性修饰,用weak修饰,self.leftV = leftV;可以写在addSubview之前或是之后,都能保证weak指向的对象不会被销毁。 */- (void)setUp{ //leftV UIView *leftV = [[UIView alloc] initWithFrame:self.view.bounds]; leftV.backgroundColor = [UIColor blueColor]; self.leftV = leftV; [self.view addSubview:leftV]; //rightV UIView *rightV = [[UIView alloc] initWithFrame:self.view.bounds]; rightV.backgroundColor = [UIColor greenColor]; self.rightV = rightV; [self.view addSubview:rightV]; //mianV UIView *mainV = [[UIView alloc] initWithFrame:self.view.bounds]; mainV.backgroundColor = [UIColor redColor]; self.mainV = mainV; [self.view addSubview:mainV];}/** * 思路总结: 1:具体思路:1:自定义控制器,在控制器的view上分别添加左右抽屉和mainview,并给mainView添加平移手势,给self.view添加轻击手势,虽然点击的是mainView或是其他的view,但是响应事件的就是self.view 2:1:在平移手势的方法中,获得平移的距离,此时改变mainView的frame有两种方法,transform累加形变或是直接更改frame,使用transform不能设置其高度,所以用更改frame的方法。将更改frame的方法封装起来外界传入偏移的x值,返回一个mainView的frame。2:1:设置frame的x值,x值是累加形变的,frame.origin.x += offsetX;并根据x值平移的比例计算y值并计算高度, CGFloat y = fabs( frame.origin.x * maxY / screenW);frame.origin.y = y;因为要考虑向左或是向右平移所以取绝对值,设置y值,并计算高度返回frame。3:在根据判断向左还是向右平移来显示或隐藏左右抽屉,(根据x值的正负来判断)4:再判断手指离开时自动复位,根据x值和最大x值和屏幕宽度的一半进行比较,来传入x值设置frame,最后将唯一归0,为了基于上次平移来计算 3:点击抽屉或是mainView来使其复原。就直接更改mainView的frame就可以了 */@end
二:抽屉效果的使用:
1:当我们用别人封装好的框架时,若不是不符合需求尽量不要修改源代码,采用继承的方式去利用别人封装好的框架
2:当我们已经在xib或是storyboard中拖进去控件的时候,此时又新建立了一个类,想与xib或是storyboard中的拖进去的控件相关联,此时可以在xib或是storyboard中去设置:
3:对于左右抽屉页面的业务逻辑处理一般不交给view处理,复杂的业务逻辑都交给控制器去处理,所以左右抽屉的view都添加控制器的view,而且当控制器的view互为父子关系时,则控制其器也应该互为父子关系
4:当我们去封装一个框架的时候,不希望外界去更改暴露的接口时,可以用readonly属性修饰。则在自身类的.m中不能用self去访问该属性变量只能用下划线的成员变量去赋值。且在外部既不能利用self去访问下划线的成员变量,也不能用下划线成员变量去访问。