QQ在这两天升级了新版本,侧滑出来的左侧菜单居然变成了全屏……
上个版本还是占屏80%的呢,而我也是参照上个版本80%屏而模仿的,以上。
效果图:
Apr-17-2019 16-28-13.gif视图层级
在Container上分别添加Main、Left、Right为子控制器;
在Container的视图上分别添加Main、Left、Right的视图;
将Main视图置于最上层,隐藏Left、Right视图;
视图层级.png
显示左侧菜单
从左往右划,显示左视图,想对平移,Main视图逐渐渐变暗,滑至指定处停止。
显示右侧菜单
从右往左划,显示右视图,想对平移,Main视图逐渐渐变暗,滑至指定处停止。
关键代码
- (void)panGuesture:(UIPanGestureRecognizer *)panGuesture {
CGPoint point = [panGuesture locationInView:panGuesture.view];
if (panGuesture.state == UIGestureRecognizerStateBegan) {
NSLog(@"Pan start");
startPoint = point;
} else if (panGuesture.state == UIGestureRecognizerStateChanged) {
//启动左视图侧滑
if (startPoint.x < RIGHT_GAP) {
_leftSideVC.view.hidden = NO;
CGFloat offset = point.x - startPoint.x;
CGFloat originX = _mainVC.view.frame.origin.x;
CGFloat finalOriginX = offset + originX;
CGFloat maxOffSet = [UIScreen mainScreen].bounds.size.width - RIGHT_GAP;
finalOriginX = finalOriginX < 0 ? 0 : finalOriginX;
finalOriginX = finalOriginX > maxOffSet ? maxOffSet : finalOriginX;
if (finalOriginX >= 0 && finalOriginX <= maxOffSet) {
_mainVC.view.frame = CGRectMake(finalOriginX, 0, CGRectGetWidth(_mainVC.view.bounds), CGRectGetHeight(_mainVC.view.bounds));
CGFloat sss = finalOriginX * (_leftSideVC.view.frame.size.width / 2.00) / maxOffSet;
_leftSideVC.view.frame = CGRectMake(- _leftSideVC.view.frame.size.width / 2.00 + sss, 0, _leftSideVC.view.frame.size.width, _leftSideVC.view.frame.size.height);
}
_mainVC.alphaView.alpha = 1.00 * finalOriginX / maxOffSet;
}
//启动右视图侧滑
if (startPoint.x > _mainVC.view.bounds.size.width - RIGHT_GAP) {
_rightSideVC.view.hidden = NO;
CGFloat offset = point.x - startPoint.x;
CGFloat originX = _mainVC.view.frame.origin.x;
CGFloat finalOriginX = offset + originX;
if (finalOriginX >= - (_mainVC.view.bounds.size.width - RIGHT_GAP) && finalOriginX <= 0) {
_mainVC.view.frame = CGRectMake(finalOriginX, 0, CGRectGetWidth(_mainVC.view.bounds), CGRectGetHeight(_mainVC.view.bounds));
CGFloat sss = -finalOriginX * (_rightSideVC.view.frame.size.width / 2.00) / (_rightSideVC.view.bounds.size.width - RIGHT_GAP);
_rightSideVC.view.frame = CGRectMake(_rightSideVC.view.frame.size.width / 2.00 - sss, 0, _rightSideVC.view.frame.size.width, _rightSideVC.view.frame.size.height);
}
_mainVC.alphaView.alpha = 1.00 * finalOriginX / (RIGHT_GAP - _mainVC.view.bounds.size.width);
}
} else if (panGuesture.state == UIGestureRecognizerStateEnded) {
NSLog(@"Pan ended");
CGPoint speedPoint = [panGuesture velocityInView:panGuesture.view];
//启动左视图侧滑
if (startPoint.x < RIGHT_GAP) {
//滑动速度大于500,类似于swip手势,直接就显示左视图。
if (speedPoint.x > 500) {
[self showLeftSideVC];
} else if (speedPoint.x < -500) {
[self hideLeftSideVC];
} else {
NSLog(@"Pan ended showAlpha = %.2f", _mainVC.alphaView.alpha);
CGFloat maxOffSet = [UIScreen mainScreen].bounds.size.width - RIGHT_GAP;
CGFloat originX = _mainVC.view.frame.origin.x;
if (originX < maxOffSet / 2.00) {
[self hideLeftSideVC];
} else {
[self showLeftSideVC];
}
}
}
//启动右视图侧滑
if (startPoint.x > _mainVC.view.bounds.size.width - RIGHT_GAP) {
//滑动速度大于500,类似于swip手势,直接就显示右视图。
if (speedPoint.x > 500) {
[self hideRightSideVC];
} else if (speedPoint.x < -500) {
[self showRightSideVC];
} else {
CGFloat maxOffSet = [UIScreen mainScreen].bounds.size.width - RIGHT_GAP;
CGFloat originX = _mainVC.view.frame.origin.x;
if (originX < - maxOffSet / 2.00) {
[self showRightSideVC];
} else {
[self hideRightSideVC];
}
}
}
startPoint = CGPointMake(0, 0);
} else if (panGuesture.state == UIGestureRecognizerStateCancelled) {
NSLog(@"Pan Canceled");
} else if (panGuesture.state == UIGestureRecognizerStateFailed) {
NSLog(@"Pan failed");
} else if (panGuesture.state == UIGestureRecognizerStatePossible) {
NSLog(@"Pan possible");
} else if (panGuesture.state == UIGestureRecognizerStateRecognized) {
NSLog(@"Pan recognized");
}
}
- (void)showLeftSideVC {
NSLog(@"showLeftSideVC");
_leftSideVC.view.hidden = NO;
CGFloat maxOffSet = [UIScreen mainScreen].bounds.size.width - RIGHT_GAP;
__weak typeof(self) weakSelf = self;
[UIView animateWithDuration:0.2 animations:^{
weakSelf.mainVC.alphaView.alpha = 1;
weakSelf.mainVC.view.frame = CGRectMake(maxOffSet, 0, weakSelf.mainVC.view.bounds.size.width, weakSelf.mainVC.view.bounds.size.height);
weakSelf.leftSideVC.view.frame = CGRectMake(0, 0, weakSelf.leftSideVC.view.frame.size.width, weakSelf.leftSideVC.view.frame.size.height);
} completion:^(BOOL finished) {
}];
}
- (void)hideLeftSideVC {
NSLog(@"hideLeftSideVC");
__weak typeof(self) weakSelf = self;
[UIView animateWithDuration:0.2 animations:^{
weakSelf.mainVC.alphaView.alpha = 0;
weakSelf.mainVC.view.frame = CGRectMake(0, 0, weakSelf.mainVC.view.bounds.size.width, weakSelf.mainVC.view.bounds.size.height);
weakSelf.leftSideVC.view.frame = CGRectMake(- weakSelf.leftSideVC.view.frame.size.width / 2.00, 0, weakSelf.leftSideVC.view.frame.size.width, weakSelf.leftSideVC.view.frame.size.height);
} completion:^(BOOL finished) {
weakSelf.leftSideVC.view.hidden = YES;
}];
}
- (void)showRightSideVC {
NSLog(@"showRightSideVC");
_rightSideVC.view.hidden = NO;
CGFloat maxOffSet = [UIScreen mainScreen].bounds.size.width - RIGHT_GAP;
__weak typeof(self) weakSelf = self;
[UIView animateWithDuration:0.2 animations:^{
weakSelf.mainVC.alphaView.alpha = 1;
weakSelf.mainVC.view.frame = CGRectMake(-maxOffSet, 0, weakSelf.mainVC.view.bounds.size.width, weakSelf.mainVC.view.bounds.size.height);
weakSelf.rightSideVC.view.frame = CGRectMake(0, 0, weakSelf.rightSideVC.view.frame.size.width, weakSelf.rightSideVC.view.frame.size.height);
} completion:^(BOOL finished) {
}];
}
- (void)hideRightSideVC {
NSLog(@"hideRightSideVC");
__weak typeof(self) weakSelf = self;
[UIView animateWithDuration:0.2 animations:^{
weakSelf.mainVC.alphaView.alpha = 0;
weakSelf.mainVC.view.frame = CGRectMake(0, 0, weakSelf.mainVC.view.bounds.size.width, weakSelf.mainVC.view.bounds.size.height);
weakSelf.rightSideVC.view.frame = CGRectMake(weakSelf.rightSideVC.view.frame.size.width / 2.00, 0, weakSelf.rightSideVC.view.frame.size.width, weakSelf.leftSideVC.view.frame.size.height);
} completion:^(BOOL finished) {
weakSelf.rightSideVC.view.hidden = YES;
}];
}
一些问题
1、手势由于添加在_mainVC.view上,如果这个_mainVC为导航控制器,则需要处理滑动手势问题,只有在根目录才可以从左往右划打开左菜单:
- (void)doPan:(UIPanGestureRecognizer *)pan {
//只有mainNVC回到根目录的时候,才可以打开侧滑菜单。
if (_mainNVC.viewControllers.count > 1) {
return;
}
}
2、假设_mainVC.view上有个tableView,tableViewCell可以左滑删除,此情况下不能打开右菜单,目前未能想到比较好的解决方案;
3、假设只有左菜单,_mainVC.view上有个tableView,tableViewCell可以左滑删除,由于pan手势直接加在_mainVC.view上,所以会造成pan手势与tableViewCell左滑删除手势冲突,导致左滑不能调起tableViewCell的侧滑事件,此时可通过手势代理相关设置来解决此办法,以下是我的解决办法:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
//当手势起始触摸点超过屏幕右侧一半的时候,忽略pan手势。
CGPoint point = [touch locationInView:touch.view];
if (point.x > _mainNVC.view.bounds.size.width / 2.0) {
return NO;
}
return YES;
}
4、关于左菜单点击事件引起的跳转问题,左菜单点击任何一个按钮,不能在左菜单的导航控制器推出,应由_mainVC的导航控制器推出,此处涉及到一个事件传递,以下是我的解决办法:
左侧菜单是一个LeftNVC,rootVC是LeftVC,主菜单是MainNVC。
a. 给LeftNVC设置一个MainNVC的属性:
#import <UIKit/UIKit.h>
#import "MainNVC.h"
@interface LeftNVC : UINavigationController
@property (strong, nonatomic) MainNVC *mainNVC;
@end
b.在ContainerVC里面将_mainNVC赋值给_leftNVC:
_leftNVC.mainNVC = _mainNVC;
c.在_leftVC里面用关联对象_mainNVC去推新页面:
#import "LeftVC.h"
#import "LeftNVC.h"
#import "CacheVC.h"
@interface LeftVC ()
@property (strong, nonatomic) LeftNVC *selfNVC;
@end
@implementation LeftVC
- (void)viewDidLoad {
[super viewDidLoad];
self.selfNVC = (LeftNVC *)self.navigationController;
}
- (IBAction)gotoCacheVC:(id)sender {
//恢复原状
if (self.selfNVC.mainNVC.tapToDissmissBlock) {
self.selfNVC.mainNVC.tapToDissmissBlock();
}
//在mainNVC推出新页面
CacheVC *vc = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"CacheVC"];
[self.selfNVC.mainNVC pushViewController:vc animated:YES];
}
网友评论