使用UIScreenEdgePanGestureRecognizer实现的侧栏,效果参考“快手”的侧栏效果
09DCF08C-D7F8-4F2D-B5FA-7E3A190E16AB.png
整体项目结构很简单如图
MainViewController 通过 addChildViewController 添加了两个 VCtrl ,分别是侧栏的VC和中间的VC(带有导航条)
向右滑动的时候,侧栏和中间的视图是有滚动差的,侧栏滚动的比较慢,而且是从左侧出来,所以侧栏VC的view的x负值,等到滑动到最大的距离,侧栏的x刚好为0
//左侧视图
self.leftVC=[[LeftViewController alloc]init];
[self addChildViewController:self.leftVC];
//中间视图,有导航
self.centerVC=[[ViewController alloc]init];
self.nav=[[BaseNavigationController alloc]initWithRootViewController:self.centerVC];
[self addChildViewController:self.nav];
[self.view addSubview:self.leftVC.view];
[self.view addSubview:self.nav.view];
//左侧x为负值,目的为了向右滑动时有左侧出来的效果,此处为屏幕宽的1/4
self.leftVC.view.frame=CGRectMake(-screenWidth/4, 0, screenWidth, screenHeight);
self.nav.view.frame=CGRectMake(0, 0, screenWidth, screenHeight);
好了 ,最重要的来了
BaseNavigationController.m
- (id)initWithRootViewController:(UIViewController *)rootViewController
{
self = [super initWithRootViewController:rootViewController];
if (self)
{
//禁止系统的侧滑
self.interactivePopGestureRecognizer.enabled=NO;
// 屏幕边缘pan手势(优先级高于其他手势)
_leftEdgeGesture = \
[[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self
action:@selector(handle:)];
_leftEdgeGesture.edges = UIRectEdgeLeft; // 屏幕左侧边缘响应
[self.view addGestureRecognizer:_leftEdgeGesture]; // 给self.view添加上
//侧栏出来时,中间视图上覆盖一层半透明的View(上图右侧黑色半透明的效果)
_view_top=[[UIView alloc]initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];
[self.view addSubview:_view_top];
_view_top.userInteractionEnabled=YES;
_view_top.backgroundColor=[UIColor blackColor];
_view_top.alpha= 0.0;
_view_top.hidden=YES;
//添加点击手势,点击回到原始状态
UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(normalState)];
[_view_top addGestureRecognizer:tap];
//添加pan手势,半透明view向左滑动
UIPanGestureRecognizer *leftPan=[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(leftPan:)];
[_view_top addGestureRecognizer:leftPan];
}
return self;
}
具体的侧滑效果就在handle :
和leftPan :
两个方法里面进行处理
//右滑方法,
- (void)handle:(UIPanGestureRecognizer *)recognizer {
//velocityInView:在指定坐标系统中pan gesture拖动的速度
//CGPoint velocity=[recognizer velocityInView:self.view];
//translationInView:获取到的是手指移动后,在相对坐标中的偏移量
CGPoint translatio=[recognizer translationInView:self.view];
if (recognizer.state == UIGestureRecognizerStateBegan ) {
NSLog(@"UIGestureRecognizerStateBegan");
self.view_top.hidden=NO;
}
if (recognizer.state == UIGestureRecognizerStateChanged) {
NSLog(@"UIGestureRecognizerStateChanged");
if (translatio.x < 0) {
return;
}
//通知,盖面MainVC中leftView和centerView的位置
[[NSNotificationCenter defaultCenter] postNotificationName:@"UIGestureRecognizerStateChanged" object:nil userInfo:@{@"width":[NSNumber numberWithFloat:translatio.x]}];
//改变半透明View的透明度
int a=(int)translatio.x;
int b=(int)kLeftWidth;
CGFloat viewAlpha=a/(CGFloat)b;
if (viewAlpha>1.0) {
self.view_top.alpha=kViewTopAlpha;
}else
self.view_top.alpha=kViewTopAlpha*viewAlpha;
}
if (recognizer.state == UIGestureRecognizerStateEnded ) {
NSLog(@"UIGestureRecognizerStateEnded");
//通知,滑动结束后,改变对一个的状态
[[NSNotificationCenter defaultCenter] postNotificationName:@"UIGestureRecognizerStateEnded" object:nil userInfo:@{@"width":[NSNumber numberWithFloat:translatio.x]}];
//滑动的距离小于最小滑动距离,状态不改变 ,反之改变
if (translatio.x <= kLeftMinWidth) {
self.view_top.hidden=YES;
}else{
self.view_top.alpha=kViewTopAlpha;
}
}
}
//半透明View左滑
- (void)leftPan:(UIPanGestureRecognizer *)recognizer {
CGPoint translatio=[recognizer translationInView:self.view];
NSLog(@"%@",NSStringFromCGPoint(translatio));
if (recognizer.state == UIGestureRecognizerStateBegan ) {
NSLog(@"UIGestureRecognizerStateBegan");
self.view_top.hidden=NO;
}
if (recognizer.state == UIGestureRecognizerStateChanged) {
NSLog(@"UIGestureRecognizerStateChanged");
if (translatio.x <= 0) {
//左滑
CGFloat widthSpace=kLeftWidth+translatio.x;
if (translatio.x <= -kLeftWidth) {
widthSpace=0.0;
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"UIGestureRecognizerStateChanged" object:nil userInfo:@{@"width":[NSNumber numberWithFloat:widthSpace]}];
//改变半透明View的透明度
int a=(int)widthSpace;
int b=(int)kLeftWidth;
CGFloat viewAlpha=a/(CGFloat)b;
self.view_top.alpha=kViewTopAlpha*viewAlpha;
}
}
if (recognizer.state == UIGestureRecognizerStateEnded ) {
NSLog(@"UIGestureRecognizerStateEnded");
//滑动的距离小于最小滑动距离,状态不改变 ,反之改变
if (translatio.x <= 0 && translatio.x >=-kLeftMinWidth) {
[[NSNotificationCenter defaultCenter] postNotificationName:@"UIGestureRecognizerStateEnded" object:nil userInfo:@{@"width":[NSNumber numberWithFloat:kLeftMinWidth]}];
}else if (translatio.x < -kLeftMinWidth) {
[[NSNotificationCenter defaultCenter] postNotificationName:@"UIGestureRecognizerStateNormal" object:nil];
[self normalState];
}
}
}
另
//右滑方法,
- (void)handle:(UIPanGestureRecognizer *)recognizer {
//只有topViewController才会触发侧栏
if (self.viewControllers.count != 1) {
return;
}
再另
如果中间视图放了一个整体的scrollView或者tabbleView,那么就会出现手势冲突
//侧滑手势触发时,禁止scrollView滚动
BaseNavigationController *navController = (BaseNavigationController *)self.navigationController;
[scrollView.panGestureRecognizer requireGestureRecognizerToFail:navController.leftEdgeGesture];