首先看效果图
思路
该嵌套滚动的视图,其外层视图是需要支持多个手势滚动的,而支持多个滚动手势的时候
拖动内层视图的时候,内外两侧视图都会滚动,
我们需要做的就是处理好什么外层视图不能滚动,什么时候内层视图不能滚动,
而我们通过 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