类似QQ侧滑菜单功能实现

时间:2021-05-30 19:25:32

之前的那文章简单实现了菜单侧拉功能,但是做不到像QQ那样导航条和tabBar一起移动。。。之后在网上找资料,有了思路,就自个写了个demo试试水。

先创建QHLMainController控制器,并把它设置成app的根控制器。

在QHLMainController控制器中,懒加载添加一个tableView,并对tableView设置相对应的属性以及frame(frame的x设置为一个负值)!!添加一个tabBar控制器,并

为tabBar控制器添加4个子控制器(分别为first,two,three,four)!!!并对tabBar控制器的view的frame 添加一个KVO监听,监听当tabBar控制器 的view的frame的改

变,并执行相对应的代码。在tabBar控制器的第一个子控制器first控制器中,添加拖动手势,当拖动时候,根据拖动的偏移量来改变自身tabBar控制器的view的frame的

值。当偏移量达到最大的时候  给view添加点击手势,当点击时候,使view的frame变回初始值!!当frame变回初值的时候,移除点击手势。

在QHLMainController控制器中

 - (void)viewDidLoad {
[super viewDidLoad]; //添加懒加载的tableView
[self.view addSubview:self.tableView]; //设置主界面
[self setUpMainUI];
} /**
* 设置主界面
*/ - (void)setUpMainUI {
//创建tabBar控制器并添加到根控制器中
QHLTabBarController *tabVc = [[QHLTabBarController alloc] init];
self.tabVc = tabVc;
[self addChildViewController:tabVc];
[self.view addSubview:tabVc.view];
//对tabBar控制器view的frame属性添加一个监听
[tabVc.view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil]; }
/**
* tabBar控制器view的frame属性的监听事件
*/ #define QHLViewControllerMaxOffsetX 250
#define QHLLeftViewOriginX -50 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
//计算偏移量
CGFloat offsetX =QHLLeftViewOriginX - QHLLeftViewOriginX * (self.tabVc.view.frame.origin.x) / QHLViewControllerMaxOffsetX;
//改变tableView的frame
CGRect frame = self.tableView.frame;
frame.origin.x = offsetX;
self.tableView.frame = frame;
}

tableView的懒加载和dataSource方法就不放上来了。

在tabBar控制器的子控制器first控制器中,先添加枚举型的结构体

 typedef NS_ENUM(NSInteger, QHLViewControllerState) {
QHLViewControllerStateClosed = ,
QHLViewControllerStateOpening,
QHLViewControllerStateOpened,
QHLViewControllerStateClosing
};

首先在viewWillAppear:中添加拖动手势,并添加到当前view中,然后在viewWillDisappear:方法中把拖动手势移除掉。

在viewDidLoad方法中:

1.把自身的state状态设置成QHLViewControllerStateClosed

2.添加navigationItem的leftBarButtonItem:封装一个UIButton,设置相关的属性设置、一个背景色以及添加一个点击方法

点击方法如下:

 /**
* leftItem的点击事件
*/
- (void)leftItemDidClick:(UIButton *)leftItem {
if (self.state == QHLViewControllerStateClosed) {
[self animatingOpen];
} else {
[self animatingClose];
}
}

拖动手势事件方法实现:

 /**
* 拖动手势的实现方法
*/
- (void)panGestureRecognized:(UIPanGestureRecognizer *)panGestureRecognizer {
CGPoint location = [panGestureRecognizer translationInView:self.view]; //位置
CGRect frame = self.tabBarController.view.frame;
//获取当前拖动手势的状态
UIGestureRecognizerState state = panGestureRecognizer.state; switch (state) {
//拖动手势开始时候
case UIGestureRecognizerStateBegan:
self.beginLocation = location; //开始位置
if (self.state == QHLViewControllerStateClosed) { [self willOpen];
} else { [self willClose];
}
break;
//拖动手势进行中
case UIGestureRecognizerStateChanged:
{
CGFloat offsetX = ; //偏移量X //根据自身的state来设置不同的offsetX
if (self.state == QHLViewControllerStateOpening) { //正在打开
offsetX = location.x - self.beginLocation.x;
} else { //正在关闭
offsetX = QHLViewControllerMaxOffsetX - (self.beginLocation.x - location.x);
} if (offsetX >= QHLViewControllerMaxOffsetX) { //偏移量超过最大偏移值时
frame.origin.x = QHLViewControllerMaxOffsetX;
} else if (offsetX <= ) { //只有在关闭时候才会出现偏移量小于0的情况,而此种情况下,偏移量小于0,会使自身的x值小于0
frame.origin.x = ;
} else { //正在打开或者正在关闭
frame.origin.x = offsetX;
} //计算透明度
CGFloat alpha = - offsetX / QHLViewControllerMaxOffsetX;
self.leftItem.alpha = alpha; //设置导航条左侧item的透明度
self.tabBarController.view.frame = frame;
break;
}
//拖动手势结束时
case UIGestureRecognizerStateEnded:
if (self.state == QHLViewControllerStateOpening) { //正在打开
if (frame.origin.x >= QHLViewControllerMaxOffsetX / ) { //判断此时的偏移量
[self animatingOpen];
} else {
[self animatingClose];
} } else { //正在关闭
if (frame.origin.x >= QHLViewControllerMaxOffsetX / ) { //判断此时的偏移量
[self animatingOpen];
} else {
[self animatingClose];
}
}
break; default:
break;
}
}

点击手势事件方法实现:

 - (void)tapGestureRecognized:(UITapGestureRecognizer *)tapGestureRecognizer {
//点击事件 自动缩回侧拉界面
[self animatingClose];
}

当tabBar控制器的view在偏移的时候,会调用下面的几个方法:

 /**
* willOpen
*/
- (void)willOpen {
self.state = QHLViewControllerStateOpening;
} /**
* opened
*/
- (void)opened {
self.state = QHLViewControllerStateOpened; //设置点击手势
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognized:)];
[self.view addGestureRecognizer:self.tapGestureRecognizer];
} /**
* willClose
*/
- (void)willClose {
self.state = QHLViewControllerStateClosing;
} /**
* closed
*/
- (void)closed {
self.state = QHLViewControllerStateClosed;
[self.view removeGestureRecognizer:self.tapGestureRecognizer];
} /**
* 以动画形式打开
*/
- (void)animatingOpen {
[UIView animateWithDuration:0.5 delay: usingSpringWithDamping:1.0 initialSpringVelocity:0.7 options:UIViewAnimationOptionCurveLinear animations:^{
self.tabBarController.view.frame = CGRectMake(QHLViewControllerMaxOffsetX, , self.view.frame.size.width, self.view.frame.size.height); self.leftItem.alpha = ;
} completion:^(BOOL finished) {
[self opened];//改变自身的state状态以及移除点击手势
}];
} /**
* 以动画形式关闭
*/
- (void)animatingClose {
[UIView animateWithDuration:0.5 delay: usingSpringWithDamping:1.0 initialSpringVelocity:0.7 options:UIViewAnimationOptionCurveLinear animations:^{
self.tabBarController.view.frame = CGRectMake(, , self.view.frame.size.width, self.view.frame.size.height); self.leftItem.alpha = ;
} completion:^(BOOL finished) {
[self closed]; //改变自身的state状态以及添加点击手势
}];
}

模拟器测试了下,基本实现了和QQ左上角的导航条item点击触发的相类似的功能~。~

如果路过的大神有更好的实现方法求指导下!!!!