抽屉效果

效果

抽屉效果
- 向右滑动显示左视图,向左滑动显示右视图
- 滑动时根据主视图的偏移量,改变主视图的大小,位置

思路
  • 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];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值