實現一個簡單的抽屜效果:
核心思想: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
