iOS学习笔记-069.手势识别03——抽屉控件实现

手势识别03—抽屉控件实现

一、预览

实现一个左右可以滑动的抽屉控件效果,如下图:

这里写图片描述

二、简单分析

实现上面的这个控件效果
1.能够拖动,说明我们可以使用,拖拽手势
2.界面有三个部分组成,左边的控件、中间的控件、右边的控件
3.这个三个界面中,我们拖拽都在中间这个控件上,所有我们可以给中间的控件添加拖拽手势
4.添加界面会发现,中间的控件会占满界面,说明需要给控制器的view添加一个敲击手势

通过以上的分析,我们可以发现,这个抽屉控件,主要有5个部分组成:

  1. 左边的控件(UIView)
  2. 中间的控件(UIView)
  3. 右边的控件(UIView)
  4. 中间控件的拖拽手势(UIPanGestureRecognizer)
  5. 控制器view的敲击手势(UITapGestureRecognizer)

ok~~~

三、创建基本布局

基本布局由左中右三个控件组成

-(void)createLayout{
    //创建leftView
    UIView * leftV = [[UIView alloc]initWithFrame:self.view.bounds];
    leftV.backgroundColor = [UIColor blueColor];
    [self.view addSubview:leftV];
    self.leftView = leftV;

    //创建rightView
    UIView * rightV = [[UIView alloc]initWithFrame:self.view.bounds];
    rightV.backgroundColor = [UIColor redColor];
    [self.view addSubview:rightV];
    self.rightView = rightV;

    //创建mainView
    UIView * mainV = [[UIView alloc]initWithFrame:self.view.bounds];
    mainV.backgroundColor = [UIColor greenColor];
    [self.view addSubview:mainV];
    self.mainView = mainV;
}

四、添加手势

布局创建好了以后,我们添加手势,主要添加两个手势:

  1. 中间控件的拖拽手势(UIPanGestureRecognizer)
  2. 控制器view的敲击手势(UITapGestureRecognizer)
-(void)addGesture{
    //给mainView添加拖动手势
    UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGesture:)];
    [self.mainView addGestureRecognizer:pan];
    //给控制器的view添加点击手势,一点击,就回到主界面上来
    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapGesture)];
    [self.view addGestureRecognizer:tap];
}

五、界面拖拽时的处理

5.1 左边和中间控件滑动分析

向右滑动

滑动的时候,如上面的图显示,图1为正常状态,此时中间的view占满屏幕,我们滑动进行分析,分析的终止点是 拖拽手势结束

向右滑动的分析

  1. 图1–>图2–>图1 : 从正常状态向右滑动,最终停留在 图2 这种状态(中间view的x(图3中的x)没有超过屏幕宽度的一半),这种情况,我们需要让它自动变为正在状态,即 图1
  2. 图1–>图3–>图4 : 从正常状态向右滑动,最终停留在 图3这种状态(中间view的x(图3中的x)超过了屏幕宽度的一半),这种情况,我们需要让它自动变为右边状态,即 图4
  3. 图4向右–>图4 :右边状态向右滑动,我们恢复到 右边状态 图4

通过上面的分析,我们得出结论:
向右滑动结束,我们只需要判断,中间控件的 x 是否超过屏幕的一半,超过了图4状态,没超过图1状态

向左滑动的分析
1. 图4–>图3–>图4
2. 图4–>图2–>图1

向左滑动,我们的判断依据还是中间view的x值(距离左边的值)。

综合上述: 左、中控件的滑动,我们只需要判断 x值(中间控件距离左边的距离)大于屏幕的一边,大于图4,小于图1


5.2 右边和中间控件滑动分析

向左滑动
向左滑动的分析

  1. 图5–>图6–>图5
  2. 图5–>图7–>图8
  3. 图8向左–>图8

向左滑动的时候:我们可以通过 中间view的最大x值(图6中的maxX)是否超过屏幕的一半来判断,没超过图8状态,超过图5状态

向右滑动的分析

  1. 图8–>图7–>图8
  2. 图8–>图6–>图5

向左滑动时候得出的结论同上。

综合上述:右、中控件滑动的时候,我们只需要判断maxX值(图6中的maxX)是否超过屏幕的一半来判断,没超过图8状态,超过图5状态

5.3 三个控件的滑动的分析

通过上面的分析,我们可以做如下的判断(拖拽结束时):

  1. 判断x值,是否超过屏幕的一半,超过了图4状态,没超过走第2步骤
  2. 判断maxX值,是否超过屏幕的一半,没超过图8状态,超过走第3步骤
  3. 恢复原来的状态
#define targetR 275
#define targetL -275
-(void)panGesture:(UIPanGestureRecognizer*)pan{
    //获取到偏移量量
    CGPoint panP =[pan translationInView:self.mainView];
    //为什么不使用transform,是因为我们还要去修改高度,使用transform,只能修改,x,y
    //self.mainV.transform = CGAffineTransformTranslate(self.mainV.transform, transP.x, 0);

    self.mainView.frame = [self frameWithOffsetX:panP.x];
    //判断拖动方向
    if (self.mainView.frame.origin.x>0) {//右
        self.rightView.hidden = YES;
    } else if(self.mainView.frame.origin.x<0){//左
        self.rightView.hidden = NO;
    }

    //自动点位计算
    //拖动结束以后做判断
    //1.x值大于一半的屏幕宽度,说明在右侧
    //2.maxX值小于一半的屏幕宽度,说明在左侧
    CGFloat target = 0;
    if(pan.state == UIGestureRecognizerStateEnded){
        if(self.mainView.frame.origin.x > 0.5*screenW){//右侧
            target = targetR;
        }else if(CGRectGetMaxX(self.mainView.frame) < 0.5*screenW){
            //获取最大的x值,判断,当前是小于屏幕的一半
            target = targetL;
        }
        //计算view的frame
        CGFloat offSet = target - self.mainView.frame.origin.x;
        [UIView animateWithDuration:0.1 animations:^{
            self.mainView.frame = [self frameWithOffsetX:offSet];
        }];
    }

    [pan setTranslation:CGPointZero inView:self.mainView];
}

#define maxY 100
//根据偏移量计算MainV的frame
- (CGRect)frameWithOffsetX:(CGFloat)offsetX {
    CGRect frame = self.mainView.frame;
    //x值的计算
    frame.origin.x += offsetX;

    //y值得计算
    //最大值是 maxY ,就是拖动的view的x值等于屏幕的宽度的时候就是这个值
    //拖动最小的时候,就是0
    //所以可以知道 y 的变化为: y = x * maxY/screenW
    CGFloat y = fabs( frame.origin.x * maxY / screenW );
    frame.origin.y = y;
    //计算高度,其实高度就是 屏幕的高度减去两倍计算的y值
    frame.size.height = [UIScreen mainScreen].bounds.size.height - 2*frame.origin.y;

    return frame;
}

六、敲击手势处理

点击屏幕,我们恢复到正常状态图1

-(void)tapGesture{
    //mainView复位
    [UIView animateWithDuration:0.1 animations:^{
        self.mainView.frame = self.view.bounds;
    }];
}

七、代码示例

//
//  DragViewController.m
//  03_UIView62_抽屉效果
//
//  Created by 杞文明 on 17/4/2.
//  Copyright © 2017年 杞文明. All rights reserved.
//

#import "DragViewController.h"

#define screenW [UIScreen mainScreen].bounds.size.width

@interface DragViewController ()
@property(weak,nonatomic)UIView* leftView;
@property(weak,nonatomic)UIView* rightView;
@property(weak,nonatomic)UIView* mainView;
@end

@implementation DragViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //创建布局
    [self createLayout];
    //添加手势
    [self addGesture];
}

-(void)createLayout{
    //创建leftView
    UIView * leftV = [[UIView alloc]initWithFrame:self.view.bounds];
    leftV.backgroundColor = [UIColor blueColor];
    [self.view addSubview:leftV];
    self.leftView = leftV;

    //创建rightView
    UIView * rightV = [[UIView alloc]initWithFrame:self.view.bounds];
    rightV.backgroundColor = [UIColor redColor];
    [self.view addSubview:rightV];
    self.rightView = rightV;

    //创建mainView
    UIView * mainV = [[UIView alloc]initWithFrame:self.view.bounds];
    mainV.backgroundColor = [UIColor greenColor];
    [self.view addSubview:mainV];
    self.mainView = mainV;

}

-(void)addGesture{
    //给mainView添加拖动手势
    UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGesture:)];
    [self.mainView addGestureRecognizer:pan];
    //给控制器的view添加点击手势,一点击,就回到主界面上来
    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapGesture)];
    [self.view addGestureRecognizer:tap];
}

-(void)tapGesture{
    //mainView复位
    [UIView animateWithDuration:0.1 animations:^{
        self.mainView.frame = self.view.bounds;
    }];
}


#define targetR 275
#define targetL -275
-(void)panGesture:(UIPanGestureRecognizer*)pan{
    //获取到偏移量量
    CGPoint panP =[pan translationInView:self.mainView];
    //为什么不使用transform,是因为我们还要去修改高度,使用transform,只能修改,x,y
    //self.mainV.transform = CGAffineTransformTranslate(self.mainV.transform, transP.x, 0);

    self.mainView.frame = [self frameWithOffsetX:panP.x];
    //判断拖动方向
    if (self.mainView.frame.origin.x>0) {//右
        self.rightView.hidden = YES;
    } else if(self.mainView.frame.origin.x<0){//左
        self.rightView.hidden = NO;
    }

    //自动点位计算
    //拖动结束以后做判断
    //1.x值大于一半的屏幕宽度,说明在右侧
    //2.maxX值小于一半的屏幕宽度,说明在左侧
    CGFloat target = 0;
    if(pan.state == UIGestureRecognizerStateEnded){
        if(self.mainView.frame.origin.x > 0.5*screenW){//右侧
            target = targetR;
        }else if(CGRectGetMaxX(self.mainView.frame) < 0.5*screenW){
            //获取最大的x值,判断,当前是小于屏幕的一半
            target = targetL;
        }
        //计算view的frame
        CGFloat offSet = target - self.mainView.frame.origin.x;
        [UIView animateWithDuration:0.1 animations:^{
            self.mainView.frame = [self frameWithOffsetX:offSet];
        }];
    }

    [pan setTranslation:CGPointZero inView:self.mainView];
}

#define maxY 100
//根据偏移量计算MainV的frame
- (CGRect)frameWithOffsetX:(CGFloat)offsetX {
    CGRect frame = self.mainView.frame;
    //x值的计算
    frame.origin.x += offsetX;

    //y值得计算
    //最大值是 maxY ,就是拖动的view的x值等于屏幕的宽度的时候就是这个值
    //拖动最小的时候,就是0
    //所以可以知道 y 的变化为: y = x * maxY/screenW
    CGFloat y = fabs( frame.origin.x * maxY / screenW );
    frame.origin.y = y;
    //计算高度,其实高度就是 屏幕的高度减去两倍计算的y值
    frame.size.height = [UIScreen mainScreen].bounds.size.height - 2*frame.origin.y;

    return frame;
}

@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值