美文网首页
实现全屏滑动,解决UIScrollerView的冲突

实现全屏滑动,解决UIScrollerView的冲突

作者: 874b526fa570 | 来源:发表于2018-02-25 23:10 被阅读192次

    实现全屏滑动,解决UIScrollerView的冲突

    之前我们追求 让你三行代码, 今天我们追求让你随便写代码,

    喜欢单手操作的我在这里我要隆重地赞美一下,今日头条,简书APP ,我喜欢他们的原因就是他们完美实现了全屏滑动,不像有些APP 还要点左上角或者屏幕边缘才能返回,这不符合单身20多年的我的习惯!

    装逼结束,下面是正文:

    今天我们要实现的是不需要写一行代码,实现全屏滑动,并且解决UIScrollerView的冲突
    先看下效果


    演示2.gif

    最后一个界面就是不要全屏滑动的界面

    创建一个 UINavigationController的分类,在分类中操作
    基础知识
    打印

    NSLog(@"---------%@",self.navigationController.interactivePopGestureRecognizer);
    

    得到的结果如下

    <UIScreenEdgePanGestureRecognizer: 0x7f9ee0c3b5a0; 
    state = Possible; 
    delaysTouchesBegan = YES;
    view = <UILayoutContainerView 0x7f9ee0c38170>; 
    target= <(action=handleNavigationTransition:
    target=<_UINavigationInteractiveTransition 0x7f9ee0c3b460>)>>
    

    系统管理全屏滑动的类是 UIScreenEdgePanGestureRecognizer 这个类
    执行者是 _UINavigationInteractiveTransition == self.interactivePopGestureRecognizer.delegate
    方法是 handleNavigationTransition

    知道上面的思路我们需要做的就是 用我们自己的手势去拦截系统的手势,然后去实现系统全屏滑动的效果 方法: <handleNavigationTransition>

    首先我们自定义手势 popPanGestureRecognizer
    他的taget 和action 还是系统的方法,但是 手势的delegate 换成 self 就是导航栏控制器
    然后通过 runtime hook 在viewWillAppear 的方法中 将自己创建的手势添加到 self.view 就是导航栏控制器

    接下来需要处理手势
    首先需要设置

    ///是否允许接收手指的触摸点
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
    {
        return self.childViewControllers.count > 1; // 只有非跟控制器才需要触发手势
    }
    

    在跟控制器中不响应

    同时还需要写下面的方法,处理手势冲突

    /// 只有当系统侧滑手势失败了,才去触发ScrollView的滑动 这个方法返回YES,第一个和第二个互斥时,第二个会失效
    /**
     第一个手势是  <UIPanGestureRecognizer: 0x7fdd5d70ac90; state = Possible; view = <UILayoutContainerView 0x7fdd5d50ff20>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fdd5d40fd60>)>>
     第二个手势是  <UIScrollViewPanGestureRecognizer: 0x7fdd5d425840; state = Possible; delaysTouchesEnded = NO; view = <UIScrollView 0x7fdd5d8ec000>; target= <(action=handlePan:, target=<UIScrollView 0x7fdd5d8ec000>)>>
     */
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {
        return YES;
    }
    

    处理完手势冲突后 需要处理 手势的作用范围,代码如下:

    ///开始进行手势识别时调用的方法是否接收一个手势触摸事件默认为YES返回NO为不接收用处:可以在控件指定的位置使用手势识别
    - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
    {
        if ([[self valueForKey:@"_isTransitioning"] boolValue])
        {
            return NO;
        }
        if ([self.navigationController.transitionCoordinator isAnimated])
        {
            return NO;
        }
        if (self.childViewControllers.count <= 1)
        {
            return NO;
        }
        BOOL res = NO;
        if (self.isEnabled == YES)
        {
            // 侧滑手势触发位置
            CGPoint location = [gestureRecognizer locationInView:self.view];
            CGPoint offSet = [gestureRecognizer translationInView:gestureRecognizer.view];
            BOOL ret = (0 < offSet.x && location.x <= self.recognizerLength);
            return ret;
        }
        return res;
    }
    
    

    如果你需要定制 在viewdidload方法中写下面的属性

     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
       这个属性控制着 左边滑动手势的区域      
            self.navigationController.recognizerLength = 100;
        });
    

    除此之外
    还可以设计成某一个界面不想要全屏滑动的设计
    给viewcontroller 添加一个分类 同时绑定一个属性控制可用与否
    具体代码如下:
    分别在 viewWillAppear 和 viewWillDisappear 对方法进行交换 和赋值

    -(void)_vcViewWillAppear:(BOOL)animated
    {
        [self _vcViewWillAppear:animated];
        if (self.noPopAction)
        {
            self.navigationController.popPanGestureRecognizer.enabled = NO;
        }
    }
    
    -(void)_vcViewWillDisAppear:(BOOL)animated
    {
        [self _vcViewWillDisAppear:animated];
        if (self.noPopAction)
        {
            self.navigationController.popPanGestureRecognizer.enabled = YES;
        }
    }
    

    实际使用的过程中中在 适当位置写上下面的代码就ok

     self.noPopAction = YES;  // 这个界面不想要全屏手势了
    

    到此不需要写一行代码就可以搞定全屏滑动,并且也不影响你自己的 UISCrollerView的手势

    同学们如果有什么建议反馈请 简书上联系我

    https://www.jianshu.com/u/874b526fa570

    同学们也别忘了支持一下我写的多张照片照片选择框架

    https://github.com/wangjinshan/IJSPhotoSDK

    本篇文档的内容将放到

    https://github.com/wangjinshan/IJSPhotoSDK 目录下 IJSNavigationBack 文件夹下 需要的小伙伴 直接下载这个文件 然后放到自己的项目中可以了,不需要写代码

    相关文章

      网友评论

          本文标题:实现全屏滑动,解决UIScrollerView的冲突

          本文链接:https://www.haomeiwen.com/subject/gzxolxtx.html