抽屉/侧拉门 效果(仿网易+改善)

首先先描述一下侧拉门的思路

步骤步骤
1.侧拉门分 三个部分: 左侧controller, 中部controller, 右侧controller
2.进入程序后首先显示的是中部controller
3.显示左右controller的方式有两种: a. 按钮 b.pan平移手势(只做了左侧的右侧有空再做)
4.隐藏左右controller的方式也有两种: a. 按钮 b.pan平移手势
5.当左侧controller处于显示状态时, 右侧controller应该是隐藏的
6.好了, 剩下的就是算法了

侧拉门控件 声明


在DrawerViewController.h中声明

@interface DrawerViewController : UIViewController

@property (strong, nonatomic) UIViewController *leftDrawerVC;
@property (strong, nonatomic) UIViewController *centerDrawerVC;
@property (strong, nonatomic) UIViewController *rightDrawerVC;

//初始化方法
- (instancetype)initWithLeftVC:(UIViewController *)leftVC
                      centerVC:(UIViewController *)centerVC
                       rightVC:(UIViewController *)rightVC;


//调用后显示或关闭左侧控制器
- (void)tapLeftDrawerButton;

//调用后显示或关闭右侧控制器
- (void)tapRightDrawerButton;

//关闭左抽屉
- (void)closeLeftDrawer;

//关闭有抽屉
- (void)closeRightDrawer;

@end

侧拉门控件 实现


在DrawerViewController.m中实现

#import "DrawerViewController.h"

#define kScreenF ([UIScreen mainScreen].bounds)
#define kStopX (kScreenF.size.width*3 / 5.50)

@interface DrawerViewController ()

///起始center的x, y
@property (nonatomic, assign) CGFloat startX;
@property (nonatomic, assign) CGFloat startY;
@property (nonatomic, assign) CGFloat startH;

///平移时 centerVC的X
@property (nonatomic, assign) CGFloat endX;

///左边抽屉 显示状态
@property(nonatomic,assign)BOOL leftDrawerIsHidden;
///右边抽屉 显示状态
@property(nonatomic,assign)BOOL rightDrawerIsHidden;
///左侧 手势
@property(nonatomic,retain)UITapGestureRecognizer *tapLeft;
///右侧 手势
@property(nonatomic,retain)UITapGestureRecognizer *tapRight;
@end

@implementation DrawerViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        self.view.backgroundColor = [UIColor whiteColor];
    }
    return self;
}

/**
 *  重写 初始化 方法
 *
 *  @param leftVC   左视图
 *  @param centerVC 中间视图
 *  @param rightVC  右视图
 *
 *  @return 抽屉视图
 */
- (instancetype)initWithLeftVC:(UIViewController *)leftVC centerVC:(UIViewController *)centerVC rightVC:(UIViewController *)rightVC {

    if (self = [super init]) {
        //加载右视图
        [self setRightDrawerVC:rightVC];
        [self.view addSubview:rightVC.view];


        //加载左视图
        [self setLeftDrawerVC:leftVC];
        [self.view addSubview:leftVC.view];


        //加载中间视图
        [self setCenterDrawerVC:centerVC];


        //设置左右抽屉的布尔值
        self.leftDrawerIsHidden = YES;
        self.rightDrawerIsHidden = YES;


        //将左控制器添加为子控制器,这样左边控制器才可以找到self
        [self addChildViewController:leftVC];

        //将右视图控制器添加为子控制器
        [self addChildViewController:rightVC];

    }
    return self;

}

/**
 *  重写设置中间视图的set方法
 */
- (void)setCenterDrawerVC:(UIViewController *)CenterDrawerVC
{
    if (_centerDrawerVC == nil) {

        _centerDrawerVC = CenterDrawerVC;
        [self.view addSubview:_centerDrawerVC.view];
        [self addChildViewController:_centerDrawerVC];


    }else{

        self.leftDrawerIsHidden = YES;
        self.rightDrawerIsHidden = YES;

        UIViewController *oldVC = _centerDrawerVC;
        _centerDrawerVC = CenterDrawerVC;
        [self.view addSubview:_centerDrawerVC.view];
        [oldVC removeFromParentViewController];
        [oldVC.view removeFromSuperview];
        [self addChildViewController:_centerDrawerVC];
    }

    [self addPanGeustureToLeft];

}

/**
 *  添加 平移手势
 */
- (void)addPanGeustureToLeft {
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGeustureAction:)];
    [self.centerDrawerVC.view addGestureRecognizer:pan];
}


/**
 *  平移手势触发 centerVC的frame的变化
 *
 *  @param .state 平移手势
 */
- (void)panGeustureAction:(UIPanGestureRecognizer *)pan {
    //如果是刚按下的状态, 记住起始x,y
    if (UIGestureRecognizerStateBegan == pan.state) {
        self.startX = self.centerDrawerVC.view.frame.origin.x;
        self.startY = self.centerDrawerVC.view.frame.origin.y;
        self.startH = self.centerDrawerVC.view.frame.size.height;
        NSLog(@"%f, %f", self.startX, self.startY);
    }

    CGPoint deltaPoint = [pan translationInView:self.view];

    self.endX = self.startX + deltaPoint.x;

    NSLog(@"--%f, --%f", self.startX, self.startY);

    if (self.endX >= 0) {
        self.centerDrawerVC.view.frame = CGRectMake(self.startX + deltaPoint.x, self.startY + deltaPoint.x / 2.0, kScreenF.size.width, self.startH - deltaPoint.x);
    }

    /**
     *  平移过程有2种情况
     1. endX 大于屏幕一半时自动跳转到 左侧打开状态
     2. 小于屏幕一半时自动跳转到 左侧关闭状态
     */
    if (UIGestureRecognizerStateEnded == pan.state) {


        if (self.endX >= kScreenF.size.width / 3.0) {
            _rightDrawerVC.view.hidden = YES;
            _leftDrawerVC.view.hidden = NO;

            [UIView animateWithDuration:0.6f animations:^{
                _centerDrawerVC.view.frame = CGRectMake(kStopX, kStopX / 2.0, 375, kScreenF.size.height - kStopX);
            }];

            _leftDrawerIsHidden = NO;

            [self AddTapGestureToLeft];

        }else if(self.endX < kScreenF.size.width / 3.0){


            [UIView animateWithDuration:0.5f animations:^{
                self.centerDrawerVC.view.frame = [UIScreen mainScreen].bounds;
            }];

            _leftDrawerIsHidden = YES;
            [self AddTapGestureToLeft];
        }
    }

}

#pragma 点击手势方法
//当左抽屉处于打开状态的时候, 在中间视图上添加单击手势,点击收回左抽屉
- (void)AddTapGestureToLeft
{
        //添加 防止额外的手势创建
          if (self.tapLeft == nil) {

        self.tapLeft = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapLeftDrawerButton)];
        }

        [_centerDrawerVC.view addGestureRecognizer:self.tapLeft];

    }else{
        if (self.tapLeft != nil) {
            [_centerDrawerVC.view removeGestureRecognizer:_tapLeft];
            [self addPanGeustureToLeft];

//            if (self.centerDrawerVC.view.frame.origin.x > 115) {
//                
//                [self tapLeftDrawerButton];
//
//            }else if (self.centerDrawerVC.view.frame.origin.x != 0
//                      && self.centerDrawerVC.view.frame.origin.x < 115){
//                [self closeLeftDrawer];
//            }
        }
    }

}

//当右抽屉处于打开状态的时候,在中间视图上添加单击手势,点击收回右抽屉
- (void)AddTapGestureToRight
{
    if (!self.rightDrawerIsHidden) {

        self.tapRight = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapRightDrawerButton)];

        [_centerDrawerVC.view addGestureRecognizer:self.tapRight];

    }else{

        if (self.tapRight != nil) {

            [_centerDrawerVC.view removeGestureRecognizer:_tapRight];
        }
    }

}

#pragma 左右button的点击事件
//左边点击事件
-(void)tapLeftDrawerButton
{
    _rightDrawerVC.view.hidden = YES;
    _leftDrawerVC.view.hidden = NO;

    if (!self.leftDrawerIsHidden) {    //zuo侧 显示 状态时

        [UIView animateWithDuration:0.5f animations:^{
            self.centerDrawerVC.view.frame = [UIScreen mainScreen].bounds;
        }];

        _leftDrawerIsHidden = YES;

        [self AddTapGestureToLeft];

    }else{                  //左侧 隐藏 状态

        [UIView animateWithDuration:0.6f animations:^{
            _centerDrawerVC.view.frame = CGRectMake(kStopX, kStopX / 2.0, 375, kScreenF.size.height - kStopX);
        }];

        _leftDrawerIsHidden = NO;

        [self AddTapGestureToLeft];
    }

}

//右边点击事件
- (void)tapRightDrawerButton
{
    _leftDrawerVC.view.hidden = YES;
    _rightDrawerVC.view.hidden = NO;

    if (!self.rightDrawerIsHidden) {

        [UIView animateWithDuration:0.5 animations:^{
            self.centerDrawerVC.view.frame = [UIScreen mainScreen].bounds;
        }];

        _rightDrawerIsHidden = YES;

        [self AddTapGestureToRight];

    }else{

        [UIView animateWithDuration:0.6f animations:^{
            _centerDrawerVC.view.frame = CGRectMake(-250, 50, 320, 400);
        }];

        _rightDrawerIsHidden = NO;

        [self AddTapGestureToRight];
    }
}

#pragma 关闭左右抽屉的快捷方法
//关闭左抽屉, 方便调用
- (void)closeLeftDrawer
{
    _centerDrawerVC.view.frame = [[UIScreen mainScreen] bounds];

    _leftDrawerIsHidden = YES;

    [self AddTapGestureToLeft];

}

//关闭右抽屉, 方便调用
- (void)closeRightDrawer
{
    _centerDrawerVC.view.frame = [[UIScreen mainScreen] bounds];

    _rightDrawerIsHidden = YES;

    [self AddTapGestureToRight];

}

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)dealloc
{
    [self.centerDrawerVC.view removeObserver:self forKeyPath:@"frame"];
}

@end

侧拉门控件 调用


然后就开始调用啦
首先在AppDelegate中, 设置我们写的抽屉控制器为根视图控制器:

    //左视图
    LeftVC *leftVC = [[LeftVC alloc] init];

    //中间视图
    CenterVC *centerVC = [[CenterVC alloc] init];
    UINavigationController *centerNC = [[UINavigationController alloc] initWithRootViewController:centerVC];

    //右视图
    RightVC *rightVC = [[RightVC alloc] init];

    self.window.rootViewController = [[DrawerViewController alloc] initWithLeftVC:leftVC centerVC:centerNC rightVC:rightVC];

在中间视图中设置两个按钮 用来控制左右控制器的显隐

- (void)viewDidLoad {
    [super viewDidLoad];

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"左侧" style:UIBarButtonItemStylePlain target:self action:@selector(openLeftAction)];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"右侧" style:UIBarButtonItemStylePlain target:self action:@selector(openRightAction)];
    self.view.backgroundColor = [UIColor redColor];

}


#pragma mark - Action
/**
 *  打开左视图
 */
- (void)openLeftAction {
    [DrawerViewController*)[self.parentViewController parentViewController] tapLeftDrawerButton];
}

/**
 *  打开右视图
 */
- (void)openRightAction {
    [DrawerViewController*)[self.parentViewController parentViewController] tapRightDrawerButton];
}

@end

然而到这里你会发现 找到DrawerViewController有点麻烦啊, 那么有没有简单一点的办法呢, 当然有

添加分类


为UIViewController写个分类

声明部分
@interface UIViewController (MyDrawer)
///方便的找到 抽屉控制器
@property(nonatomic,strong,readonly)DrawerViewController *getDrawerViewController;

@end

实现部分
- (DrawerViewController *)getDrawerViewController{

    if([self.parentViewController isKindOfClass:[DrawerViewController class]]){

        return (DrawerViewController*)self.parentViewController;

    }else if([self.parentViewController isKindOfClass:[UINavigationController class]] &&
             [self.parentViewController.parentViewController isKindOfClass:[DrawerViewController class]]){

        return (DrawerViewController*)[self.parentViewController parentViewController];

    }else{

        return nil;
    }
}

那我们上面 打开关闭左右视图就方便了

#pragma mark - Action
/**
 *  打开左视图
 */
- (void)openLeftAction {
    [[self getDrawerViewController] tapLeftDrawerButton];
}

/**
 *  打开右视图
 */
- (void)openRightAction {
    [self.getDrawerViewController tapRightDrawerButton];
}

来几张效果图(仅仅是个demo, 界面未做优化)
中间控制器
左侧控制器
右侧控制器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值