首先先描述一下侧拉门的思路
步骤 | 步骤 |
---|---|
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, 界面未做优化)