类似QQ侧滑菜单功能实现

之前的那文章简单实现了菜单侧拉功能,但是做不到像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控制器中

 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     
 4     //添加懒加载的tableView
 5     [self.view addSubview:self.tableView];
 6     
 7     //设置主界面
 8     [self setUpMainUI];
 9 }
10 
11 /**
12  *  设置主界面
13  */
14 
15 - (void)setUpMainUI {
16     //创建tabBar控制器并添加到根控制器中
17     QHLTabBarController *tabVc = [[QHLTabBarController alloc] init];
18     self.tabVc = tabVc;
19     [self addChildViewController:tabVc];
20     [self.view addSubview:tabVc.view];
21     //对tabBar控制器view的frame属性添加一个监听
22     [tabVc.view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
23     
24 }
25 /**
26  *  tabBar控制器view的frame属性的监听事件
27  */
28 
29 #define QHLViewControllerMaxOffsetX 250
30 #define QHLLeftViewOriginX -50
31 
32 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
33     //计算偏移量
34     CGFloat offsetX =QHLLeftViewOriginX - QHLLeftViewOriginX * (self.tabVc.view.frame.origin.x) / QHLViewControllerMaxOffsetX;
35     //改变tableView的frame
36     CGRect frame = self.tableView.frame;
37     frame.origin.x = offsetX;
38     self.tableView.frame = frame;
39 }

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

 

 

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

1 typedef NS_ENUM(NSInteger, QHLViewControllerState) {
2     QHLViewControllerStateClosed = 0,
3     QHLViewControllerStateOpening,
4     QHLViewControllerStateOpened,
5     QHLViewControllerStateClosing
6 };

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

在viewDidLoad方法中:

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

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

点击方法如下:

 1 /**
 2  *  leftItem的点击事件
 3  */
 4 - (void)leftItemDidClick:(UIButton *)leftItem {
 5     if (self.state == QHLViewControllerStateClosed) {
 6         [self animatingOpen];
 7     } else {
 8         [self animatingClose];
 9     }
10 }

拖动手势事件方法实现:

 1 /**
 2  *  拖动手势的实现方法
 3  */
 4 - (void)panGestureRecognized:(UIPanGestureRecognizer *)panGestureRecognizer {
 5     CGPoint location = [panGestureRecognizer translationInView:self.view];  //位置
 6     CGRect frame = self.tabBarController.view.frame;
 7     //获取当前拖动手势的状态
 8     UIGestureRecognizerState state = panGestureRecognizer.state;
 9     
10     switch (state) {
11             //拖动手势开始时候
12         case UIGestureRecognizerStateBegan:
13             self.beginLocation = location; //开始位置
14             if (self.state == QHLViewControllerStateClosed) {
15 
16                 [self willOpen];
17             } else {
18 
19                 [self willClose];
20             }
21             break;
22             //拖动手势进行中
23         case UIGestureRecognizerStateChanged:
24         {
25             CGFloat offsetX = 0;   //偏移量X
26             
27             //根据自身的state来设置不同的offsetX
28             if (self.state == QHLViewControllerStateOpening) {  //正在打开
29                 offsetX = location.x - self.beginLocation.x;
30             } else {   //正在关闭
31                 offsetX = QHLViewControllerMaxOffsetX - (self.beginLocation.x - location.x);
32             }
33 
34             if (offsetX >= QHLViewControllerMaxOffsetX) { //偏移量超过最大偏移值时
35                 frame.origin.x = QHLViewControllerMaxOffsetX;
36             } else if (offsetX <= 0) { //只有在关闭时候才会出现偏移量小于0的情况,而此种情况下,偏移量小于0,会使自身的x值小于0
37                 frame.origin.x = 0;
38             } else { //正在打开或者正在关闭
39                 frame.origin.x = offsetX;
40             }
41             
42             //计算透明度
43             CGFloat alpha = 1 - offsetX / QHLViewControllerMaxOffsetX;
44             self.leftItem.alpha = alpha; //设置导航条左侧item的透明度
45             self.tabBarController.view.frame = frame;
46             break;
47         }
48             //拖动手势结束时
49         case UIGestureRecognizerStateEnded:
50             if (self.state == QHLViewControllerStateOpening) { //正在打开
51                 if (frame.origin.x >= QHLViewControllerMaxOffsetX / 2) { //判断此时的偏移量
52                     [self animatingOpen];
53                 } else {
54                     [self animatingClose];
55                 }
56                 
57             } else { //正在关闭
58                 if (frame.origin.x >= QHLViewControllerMaxOffsetX / 2) { //判断此时的偏移量
59                     [self animatingOpen];
60                 } else {
61                     [self animatingClose];
62                 }
63             }
64             break;
65             
66         default:
67             break;
68     }
69 }

点击手势事件方法实现:

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

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

 1 /**
 2  * willOpen
 3  */
 4 - (void)willOpen {
 5     self.state = QHLViewControllerStateOpening;
 6 }
 7 
 8 /**
 9  * opened
10  */
11 - (void)opened {
12     self.state = QHLViewControllerStateOpened;
13     
14     //设置点击手势
15     self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognized:)];
16     [self.view addGestureRecognizer:self.tapGestureRecognizer];
17 }
18 
19 /**
20  * willClose
21  */
22 - (void)willClose {
23     self.state = QHLViewControllerStateClosing;
24 }
25 
26 /**
27  * closed
28  */
29 - (void)closed {
30     self.state = QHLViewControllerStateClosed;
31     [self.view removeGestureRecognizer:self.tapGestureRecognizer];
32 }
33 
34 /**
35  *  以动画形式打开
36  */
37 - (void)animatingOpen {
38     [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:1.0 initialSpringVelocity:0.7 options:UIViewAnimationOptionCurveLinear animations:^{
39         self.tabBarController.view.frame = CGRectMake(QHLViewControllerMaxOffsetX, 0, self.view.frame.size.width, self.view.frame.size.height);
40         
41         self.leftItem.alpha = 0;
42     } completion:^(BOOL finished) {
43         [self opened];//改变自身的state状态以及移除点击手势
44     }];
45 }
46 
47 /**
48  *  以动画形式关闭
49  */
50 - (void)animatingClose {
51     [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:1.0 initialSpringVelocity:0.7 options:UIViewAnimationOptionCurveLinear animations:^{
52         self.tabBarController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
53         
54         self.leftItem.alpha = 1;
55     } completion:^(BOOL finished) {
56         [self closed];  //改变自身的state状态以及添加点击手势
57     }];
58 }

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

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

原文地址:https://www.cnblogs.com/qhlbk/p/5122947.html