之前的那文章简单实现了菜单侧拉功能,但是做不到像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点击触发的相类似的功能~。~
如果路过的大神有更好的实现方法求指导下!!!!