#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去訪問下划線的成員變量,也不能用下划線成員變量去訪問。