實現一個簡單的抽屜效果:
核心思想:KVO實現監聽mainV的frame值的變化
核心代碼:
#import "ViewController.h" // @"frame" #define XMGkeyPath(objc, keyPath) @(((void)objc.keyPath, #keyPath)) // 在宏里面如果在參數前添加了#,就會把參數變成C語言字符串 // 獲取屏幕的寬度 #define screenW [UIScreen mainScreen].bounds.size.width // 獲取屏幕的高度 #define screenH [UIScreen mainScreen].bounds.size.height @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 添加所有的子控件 [self setUpAllChildView]; // 添加拖拽手勢 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; [_mainV addGestureRecognizer:pan]; // KVO作用:時刻監聽某個對象的某個屬性的改變 // _main frame屬性的改變 // Observer:觀察者 // KeyPath:監聽的屬性 // NSKeyValueObservingOptionNew:表示監聽新值的改變 [_mainV addObserver:self forKeyPath:XMGkeyPath(_mainV, frame) options:NSKeyValueObservingOptionNew context:nil]; // 給控制器的view添加一個點按 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)]; [self.view addGestureRecognizer:tap]; } - (void)tap { if (_mainV.frame.origin.x != 0) { // 把_mainV還原最開始的位置 [UIView animateWithDuration:0.25 animations:^{ _mainV.frame = self.view.bounds; }]; } } // 只要監聽的屬性一改變,就會調用 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (_mainV.frame.origin.x > 0) { // 往右滑動,顯示左邊控件,隱藏右邊控件 _rightV.hidden = YES; }else if (_mainV.frame.origin.x < 0){ // 往左滑動,顯示右邊控件 _rightV.hidden = NO; } } // 注意:當對象被銷毀的時候,一定要注意移除觀察者 - (void)dealloc { // 移除觀察者 [_mainV removeObserver:self forKeyPath:XMGkeyPath(_mainV, frame)]; } #define targetR 300 #define targetL -230 - (void)pan:(UIPanGestureRecognizer *)pan { // 獲取手勢的偏移量 CGPoint transP = [pan translationInView:_mainV]; // 獲取x軸的偏移量,相對於上一次 CGFloat offsetX = transP.x; // 修改最新的main.frame, _mainV.frame = [self frameWithOffsetX:offsetX]; // 復位 [pan setTranslation:CGPointZero inView:_mainV]; // 判斷下當前手指有沒有抬起,表示手勢結束 if (pan.state == UIGestureRecognizerStateEnded) { // 手指抬起,定位 // x>屏幕的一半,定位到右邊某個位置 CGFloat target = 0; if (_mainV.frame.origin.x > screenW * 0.5) { target = targetR; }else if (CGRectGetMaxX(_mainV.frame) < screenW * 0.5){ // 最大的x < 屏幕一半的時候,定義到左邊某個位置 target = targetL; } // 獲取x軸的偏移量 CGFloat offsetX = target - _mainV.frame.origin.x; [UIView animateWithDuration:0.25 animations:^{ _mainV.frame = [self frameWithOffsetX:offsetX]; }]; } } #define XMGMaxY 100 // 給定一個x軸的偏移量計算下最新main的frame - (CGRect)frameWithOffsetX:(CGFloat)offsetX { // 獲取當前main的frame CGRect frame = _mainV.frame; // 計算當前的x,y,w,h // 獲取最新的x CGFloat x = frame.origin.x + offsetX; // 獲取最新的y CGFloat y = x / screenW * XMGMaxY; // 當用戶往左邊移動的時候,_main.x < 0,y需要增加,為正 if (frame.origin.x < 0) { y = -y; } // 獲取最新的h CGFloat h = screenH - 2 * y; // 獲取縮放比例 CGFloat scale = h / screenH; // 獲取最新的w CGFloat w = screenW * scale; return CGRectMake(x, y, w, h); } // 添加所有的子控件 - (void)setUpAllChildView { // left UIView *leftV = [[UIView alloc] initWithFrame:self.view.bounds]; leftV.backgroundColor = [UIColor greenColor]; [self.view addSubview:leftV]; _leftV = leftV; // right UIView *rightV = [[UIView alloc] initWithFrame:self.view.bounds]; rightV.backgroundColor = [UIColor blueColor]; [self.view addSubview:rightV]; _rightV = rightV; // main UIView *mainV = [[UIView alloc] initWithFrame:self.view.bounds]; mainV.backgroundColor = [UIColor redColor]; [self.view addSubview:mainV]; _mainV = mainV; } @end
用法:
繼承ViewController
實現如下代碼即可:
#import "SlideViewController.h" @interface SlideViewController () @end @implementation SlideViewController - (void)viewDidLoad{ [super viewDidLoad]; NSLog(@"%s",__func__); // 創建一個tableView控制器 UITableViewController *tableVc = [[UITableViewController alloc] init]; tableVc.view.frame = self.mainV.bounds; [self.mainV addSubview:tableVc.view]; // 設計原理,如果A控制器的view成為b控制器view的子控件,那么這個A控制器必須成為B控制器的子控制器 [self addChildViewController:tableVc]; UIViewController *VC = [[UIViewController alloc] init]; UIImageView *imagev = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"胸小別講話"]]; // imagev.contentMode = UIViewContentModeScaleAspectFill; imagev.frame = VC.view.frame; [VC.view addSubview:imagev]; [self.rightV addSubview:VC.view]; [self addChildViewController:VC]; } @end
github地址:https://github.com/chglog/drawer