iOS-UIScreenEdgePanGestureRecognizer实现侧栏

使用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];

demo:https://github.com/chjwrr/LeftSideMenu/tree/master

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一种新的协议。它实...
    香橙柚子阅读 24,133评论 8 183
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,259评论 4 61
  • 自公元228年开启北伐战争,到公元234年诸葛亮于五丈原逝世,在这6年时间里蜀国历经5次北伐战争,虽然战果颇丰,但...
    凌Zero阅读 2,178评论 2 10
  • 落雨喽~ 小吧辣子开会喽~ 这是小时候最常听的童谣 可是这边的雨也下的太久了 淅淅沥沥 哗哗啦啦 轰轰隆隆 下了大...
    Whistlence阅读 206评论 0 0
  • 2016我来到一个陌生的城市,在这座陌生的城市里我把陌生人变为挚友,又将挚友弄丢变为恐怕几年也难以忘记的遗憾...
    胖迪的秘密男友阅读 277评论 0 1