一个iOS嵌套滚动框架

首先看效果图

请添加图片描述

思路

该嵌套滚动的视图,其外层视图是需要支持多个手势滚动的,而支持多个滚动手势的时候
拖动内层视图的时候,内外两侧视图都会滚动,
我们需要做的就是处理好什么外层视图不能滚动,什么时候内层视图不能滚动,
而我们通过 scrollView.contentOffset = CGPointMake(0, _lastDy)这种方法(即设置成
和上次滚动相同的偏移量),来实现不滚动的效果

外层不滚动的时机,超过最大偏移量,小于最小偏移量,处在临界偏移量的时候,要根据
滚动方向,和内层偏移量来确定是否滚动

核心功能代码

支持多个手势

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    UIView *otherGestureRecognizerView = otherGestureRecognizer.view;

    if( [otherGestureRecognizerView isKindOfClass:[UIScrollView class]] && otherGestureRecognizerView != self && gestureRecognizer == self.panGestureRecognizer && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {

        if([self.viewArray containsObject:(UIScrollView *)otherGestureRecognizerView]) {

            return YES;
        } else {

            return NO;
        }
    }
    return NO;
}

重写 shouldReceiveTouch 方法

这里是为了获取当前的子滚动视图

//1
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if(gestureRecognizer == self.panGestureRecognizer) {
        self.isScrolBySelf = YES;
        self.currentSubScrolleView = nil;
        UIView *touchView = touch.view;
        BOOL isContain = NO;
        while (touchView != nil) {
            if(touchView == self.viewPager) {
                isContain = YES;
                break;
            }
            touchView = [touchView nextResponder];
        }
        if(isContain) {
            touchView = touch.view;
            while (touchView != nil) {
                
                if([touchView isKindOfClass:[UIScrollView class]] && touchView != self) {
                    BOOL canContain = NO;
                    NSInteger scrollCount = 0;
                    UIView *tempView = touchView;
                    while (tempView != self.viewPager) {
                        if([tempView isKindOfClass:[UIScrollView class]]) {
                            scrollCount++;
                        }
                        tempView = [tempView nextResponder];
                    }
                    if(scrollCount == 2 && ((UIScrollView *)touchView).contentSize.width <= touchView.frame.size.width) {
                        canContain = YES;
                    }
                    if(canContain) {
                        self.isScrolBySelf = NO;
                        self.currentSubScrolleView = (UIScrollView *)touchView;
                        if(![self.viewArray containsObject:self.currentSubScrolleView]) {
                            [self.viewArray addObject:self.currentSubScrolleView];
                            [self.currentSubScrolleView addObserver:self.superview forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
                        }
                        break;
                    }
                }
                if(touchView == self.viewPager) {
                    break;
                }
                touchView = [touchView nextResponder];
            }
        }
        
    }
    return YES;
}

控制外层视图的滚动

- (void)headViewSuckTopTypeScrollViewDidScroll:(UIScrollView *)scrollView{
    CGFloat dh = scrollView.contentOffset.y;
    if (dh >= _stayHeight) {
        scrollView.contentOffset = CGPointMake(0, _stayHeight);
        _lastDy = scrollView.contentOffset.y;
    } else if(dh<=0) {
        scrollView.contentOffset = CGPointMake(0, 0);
        _lastDy = scrollView.contentOffset.y;

    } else {
        UIScrollView *currenSubScrollView = self.mainScrollView.currentSubScrolleView;//nil;
        if (currenSubScrollView == nil) {
            _lastDy = scrollView.contentOffset.y;
            return;
        }
        if(currenSubScrollView.contentOffset.y > 0 && (scrollView.contentOffset.y - _lastDy)<0  && self.mainScrollView.isScrolBySelf == NO) {
            //向下拖拽
            scrollView.contentOffset = CGPointMake(0, _lastDy);
        } else if((scrollView.contentOffset.y - _lastDy)>0 && currenSubScrollView.contentOffset.y<0) {
            //向上
            scrollView.contentOffset = CGPointMake(0, _lastDy);
        }
        _lastDy = scrollView.contentOffset.y;
    }
}

控制子视图的滚动

//subScrollView
- (void)headViewSuckTopTypeObserveValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    if (_nextReturn) {
        _nextReturn = false;
        return;
    }
    CGFloat new = [change[@"new"] CGPointValue].y;
    CGFloat old = [change[@"old"] CGPointValue].y;
    if (new == old) {return;}
    CGFloat dh = new - old;
    if (dh < 0) {
        //向下
        if(((UIScrollView *)object).contentOffset.y < 0){
            if (self.mainScrollView.contentOffset.y > 0) {
                _nextReturn = true;
                ((UIScrollView *)object).contentOffset = CGPointMake(0, 0);
            }
        }
    }else{
        //向上
        if (self.mainScrollView.contentOffset.y < _stayHeight) {
            if (((UIScrollView *)object).contentOffset.y > 0) {
                _nextReturn = true;
                if(old < 0) {
                    old = 0;
                }
                ((UIScrollView *)object).contentOffset = CGPointMake(0, old);
            }
        }else{
        }
    }
}

使用方法


- (LBNestScrollPageView *)nestView
{
    if (!_nestView) {
        LBNestScrollParam *nestScrollParam = [[LBNestScrollParam alloc] init];
        _nestView = [[LBNestScrollPageView alloc] initWithFrame:CGRectMake(0, 40, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - 40)  headView:self.headerView viewPageView:self.containerView nestScrollParam:nestScrollParam];
    }
    return _nestView;
}

pod库地址: link

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值