scrollview嵌套tableview极简解决方案

遇到了这个需求,恶心了自己一天,记录下来

嵌套模式

一个竖向滑动的scrollview1,嵌套一个横向滑动的scrollview2, 嵌套4个用controller控制的tableview

核心解决方案

  1. 手动控制contentOffset滚动的临界偏移量
  2. 打开手势穿透

控制临偏界偏移量

既然要控制临界偏移量,就首先要获取contentOffset才可以控制。

  1. 添加UIScrollviewDelegate
  2. tableview的contentoffset写一个代理返回回来,方便一起控制

手势穿透

我使用了一个分类,添加了一个属性,使得scrollview1允许穿透

/// .h文件
@interface UIScrollView (DDScrollView) 

/// 手势穿透
@property (nonatomic, strong) NSString *shouldThrough;

@end


/// .m文件

#import "UIScrollView+DDScrollView.h"
#import 


@implementation UIScrollView (DDScrollView)

- (void)setShouldThrough:(NSString *)shouldThrough {
    objc_setAssociatedObject(self, "shouldThrough", shouldThrough, OBJC_ASSOCIATION_RETAIN);
}

- (NSString *)shouldThrough {
    return objc_getAssociatedObject(self, "shouldThrough");
}


- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {

    if ([self.shouldThrough isEqualToString:@"1"]) {
        return true;
    }
    
    return false;
}

@end

核心代码

@interface ViewController ()

@property (nonatomic, strong) UIScrollView *scrollview1;

@property (nonatomic, strong) UIScrollView *scrollview2;
/// 滚动标题
@property (nonatomic, strong) PageTitleView *titleView;

@property (nonatomic, strong) NSMutableArray *childVCArr;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _childVCArr = [NSMutableArray array];
    
    _scrollview1 = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 88, self.view.frame.size.width, self.view.frame.size.height - 88)];
    _scrollview1.contentSize = CGSizeMake(0, 1000);
    _scrollview1.backgroundColor = [UIColor systemPinkColor];
    _scrollview1.tag = 500;
    _scrollview1.delegate = self;
    _scrollview1.shouldThrough = @"1";
    
    _titleView = [[PageTitleView alloc] initWithFrame:CGRectMake(0, 250, self.view.frame.size.width, 50) titles:@[@"标题1",@"标题2",@"标题3",@"标题4"]];
    _titleView.backgroundColor = [UIColor whiteColor];
    
    _scrollview2 = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 300, self.view.frame.size.width, 700)];
    _scrollview2.contentSize = CGSizeMake(self.view.frame.size.width * 4, 0);
    _scrollview2.backgroundColor = [UIColor blueColor];
    _scrollview2.tag = 501;
    _scrollview2.pagingEnabled = true;
    _scrollview2.delegate = self;
    
    [self.view addSubview:_scrollview1];
    [_scrollview1 addSubview:_titleView];
    [_scrollview1 addSubview:_scrollview2];
    
    for (int i = 0; i < 4; i ++) {
        TBController *tbvc = [[TBController alloc] init];
        tbvc.delegate = self;
        [self addChildViewController:tbvc];
        UIView *view = tbvc.view;
        CGRect rect = view.frame;
        rect.origin.x = self.view.frame.size.width * i;
        rect.size.height = _scrollview2.frame.size.height;
        view.frame = rect;
        [_scrollview2 addSubview:view];
        [_childVCArr addObject:tbvc];
    }
    
}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.tag == 500) {

        TBController *currentVc = self.childVCArr[_titleView.currentIndex];
        // 临界偏移量 245  小于245的话不允许下方滚动
        // 这个scrollview把属性穿透打开了,所以要自己控制一下偏移量
        if (scrollView.contentOffset.y < 245) {
            // 如果当前显示tablview的偏移量大于0, 则固定scrollview,让tableview滚动完再移动scrollview的
            if (currentVc.tableView.contentOffset.y > 0) {
                scrollView.contentOffset = CGPointMake(0, 245);
            } else {
                currentVc.tableView.contentOffset = CGPointMake(0, 0);
            }
        } else if (scrollView.contentOffset.y >= 245) {
            //contentoffset-y 如果小于0 静止滚动
            _scrollview1.contentOffset = CGPointMake(0, 245);
            if (currentVc.tableView.contentOffset.y < 0) {
                currentVc.tableView.contentOffset = CGPointMake(0, 0);
            } else {
                
            }
        }

    } else if (scrollView.tag == 501) {
        [_titleView moveIndicatorViewWithOffset:_scrollview2.contentOffset.x];
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    if (scrollView.tag == 501) {
        NSInteger index = scrollView.contentOffset.x / _scrollview2.frame.size.width;

        [_titleView selectCurrentTitleViewWithIndex:index];
    }
}
#pragma mark TaskListControllerDelegate
// 这里控制一下控制器内tableview返回的数值
- (void)controller:(UIViewController *)controller didScrollTableView:(UITableView *)tableView {
    [self handleOutScrollView:_scrollview1 tableView:tableView];
}


- (void)handleOutScrollView:(UIScrollView *)scrollView tableView:(UITableView *)tableView {
    if (scrollView.contentOffset.y < 245) {
        // 禁止滚动 && 自动滚到最上
        tableView.contentOffset = CGPointMake(0, 0);
    } else if (scrollView.contentOffset.y >= 245) {
        if (tableView.contentOffset.y < 0) {
            tableView.contentOffset = CGPointMake(0, 0);
        }
    }
}


#pragma mark - PageTitleViewDelegate
- (void)pageTitleIndicatorViewSelected:(NSInteger)index {
    //将scrollView滑动到指定地
    [_scrollview2 setContentOffset:CGPointMake(_scrollview2.frame.size.width * index, 0) animated:NO];
}

@end

git代码

你可能感兴趣的:(scrollview嵌套tableview极简解决方案)