效果
- 向右滑动显示左视图,向左滑动显示右视图
- 滑动时根据主视图的偏移量,改变主视图的大小,位置
思路
- 1.在中间view上添加一个拖拽手势
- 2.在拖拽方法中拿到X偏移量,设置修改当前view的frame
- 3.设置显示左边View还是右边View,通过KVO监听当前view的x值正负
- 4.当松手时,设置最后定位在那边。监听手势状态,根据当前松手时位置,进行位置判断,设置偏移量,确定最后的位置
demo代码
// 直接在宏的参数前添加#,就可以生成这个参数的c的字符串
#define keyPath(objc,keyPath) @(((void)objc.keyPath, #keyPath))
#import "DragViewController.h"
// 获取下屏幕的宽度
#define screenW [UIScreen mainScreen].bounds.size.width
@interface DragViewController ()
@end
@implementation DragViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// 添加所有子控件
[self setUpChildView];
// 添加手势
[self setUpGestureRecognizer];
// 监听mainView.frame改变
[self setUpKVO];
}
// 添加手势
- (void)setUpGestureRecognizer
{
// 给mainView添加手势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[_mainView addGestureRecognizer:pan];
// 给控制器的view添加点按手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];
[self.view addGestureRecognizer:tap];
}
- (void)tap
{
if (_mainView.frame.origin.x != 0) {
// 还原
[UIView animateWithDuration:0.25 animations:^{
_mainView.frame = self.view.bounds;
}];
}
}
// 监听mainView.frame改变
- (void)setUpKVO
{
// KVO:只要想要时刻监听某个对象的某个属性改变,就使用KVO
// 监听mainView.frame改变
// 用法: 需要观察谁,就拿到谁,给他添加观察者
// Observer:观察者
// KeyPath:观察的属性
// NSKeyValueObservingOptionNew:观察有没有新的值
[_mainView addObserver:self forKeyPath:keyPath(_mainView, frame) options:NSKeyValueObservingOptionNew context:nil];
}
#define rightTargetX 300
#define leftTargetX -200
// 当手指在mainView移动的时候就会调用
- (void)pan:(UIPanGestureRecognizer *)pan
{
// 获取x轴偏移量
CGFloat offsetX = [pan translationInView:_mainView].x;
// 修改_mainView的frame
_mainView.frame = [self frameWithOffsetX:offsetX];
// 复位
[pan setTranslation:CGPointZero inView:_mainView];
// 当手指抬起的时候,定位
if (pan.state == UIGestureRecognizerStateEnded) {
NSLog(@"手指抬起");
CGFloat targat = 0;
if (_mainView.frame.origin.x > screenW * 0.5) {
// 判断下main.x > screenW * 0.5, 定位到右边某个位置(rightTargetX)
targat = rightTargetX;
}else if (CGRectGetMaxX(_mainView.frame) < screenW * 0.5){
// max(mainView) < screenW * 0.5 定位到leftTargetX
targat = leftTargetX;
}
// 计算x轴偏移量
CGFloat offsetX = targat - _mainView.frame.origin.x;
[UIView animateWithDuration:0.25 animations:^{
// 计算最新frame
_mainView.frame = [self frameWithOffsetX:offsetX];
}];
}
}
// 只要监听的frame属性有新值,就会调用这个方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (_mainView.frame.origin.x > 0) { // 当mainView.x > 0 显示左边视图
_rightView.hidden = YES;
}else if (_mainView.frame.origin.x < 0){ // 当mainView.x < 0 显示右边视图
_rightView.hidden = NO;
}
}
#define maxY 100
// 根据x轴偏移量计算下当前mainView最新的frame
- (CGRect)frameWithOffsetX:(CGFloat)offsetX
{
CGFloat screenH = [UIScreen mainScreen].bounds.size.height;
// 获取上一次mainView的frame
CGRect frame = _mainView.frame;
// 获取最新的x
CGFloat x = frame.origin.x += offsetX;
// 获取最新的y
CGFloat y = fabs(x / screenW * maxY);
// 获取最新的高度
CGFloat h = screenH - 2 * y;
// 获取缩放比例
CGFloat scale = h / screenH;
// 获取最新的宽度
CGFloat w = screenW * scale;
return CGRectMake(x, y, w, h);
}
// 添加所有子控件
- (void)setUpChildView
{
// left
UIView *leftView = [[UIView alloc] initWithFrame:self.view.bounds];
leftView.backgroundColor = [UIColor greenColor];
UIImageView *leftImage = [[UIImageView alloc]initWithFrame:self.view.bounds];
leftImage.image = [UIImage imageNamed:@"1"];
[leftView addSubview:leftImage];
_leftView = leftView;
[self.view addSubview:leftView];
// right
UIView *rightView = [[UIView alloc] initWithFrame:self.view.bounds];
rightView.backgroundColor = [UIColor blueColor];
UIImageView *rightImage = [[UIImageView alloc]initWithFrame:self.view.bounds];
rightImage.image = [UIImage imageNamed:@"3"];
[rightView addSubview:rightImage];
_rightView = rightView;
[self.view addSubview:rightView];
// main
UIView *mainView = [[UIView alloc] initWithFrame:self.view.bounds];
mainView.backgroundColor = [UIColor redColor];
_mainView = mainView;
[self.view addSubview:mainView];
}
使用:
对外提供三个视图接口,只用创建一个继承它的子控制器,可以直接使用
#import <UIKit/UIKit.h>
@interface DragViewController : UIViewController
@property (nonatomic, weak, readonly) UIView *mainView;
@property (nonatomic, weak, readonly) UIView *leftView;
@property (nonatomic, weak, readonly) UIView *rightView;
@end
使用注意:
如果A控制器的view称为B控制器的view的子控件,那么A控制器成为B控制器的子控制器
UITableViewController *tableVc = [[UITableViewController alloc] init];
tableVc.view.frame = self.mainView.bounds;
[self.mainView addSubview:tableVc.view];
// 添加子控制器
[self addChildViewController:tableVc];