滑动手势冲突

多层Scrollview嵌套,

920 发布: 2020/7/4 01:52 本文总阅读量

多层Scrollview嵌套 【scroll顶部刷新】

底部是一个scrllview,子类是collectionview,要求向上滑动的时候scrllviewcollectionview可以做到连续滑动

约定: 底部ScollView我们称之为MainScroll,子类CollectionView称之为SubCollectionView

首先我们写一个ScrollView的基类

@interface RKScrollView : UIScrollView<UIGestureRecognizerDelegate>

@end

@implementation HoverPageScrollView

- (BOOL)touchesShouldCancelInContentView:(UIView *)view{
    return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    
    return YES;
}
@end

MainScrollView继承RKScrollView

    //注意这里父类有个属性_canScroll默认设置为YES
    _canScroll = YES;

    _mainScrollview = [[RKScrollView alloc]initWithFrame:CGRectMake(0, 0, _window_width, _window_height-78-statusbarHeight-ShowDiff-49)];
    _mainScrollview.backgroundColor = [UIColor whiteColor];
    _mainScrollview.contentSize = CGSizeMake(0, _mainScrollview.height+400);

    //重要属性【如果需要下拉刷新可在didscroll代理中更改此属性】
    _mainScrollview.bounces = NO;
    ybWeakSelf;
    MJRefreshNormalHeader *mjheader= [MJRefreshNormalHeader headerWithRefreshingBlock:^{
        [weakSelf mainScrollRefresh];
    }];
    _mainScrollView.mj_header = mjheader;
    mjheader.stateLabel.textColor = [UIColor whiteColor];
    mjheader.lastUpdatedTimeLabel.textColor = [UIColor whiteColor];
    mjheader.loadingView.color = [UIColor whiteColor];

    _mainScrollview.delegate = self;
    _mainScrollview.scrollViewWhites = [NSMutableArray array];
    [self.view addSubview:_mainScrollview];
-(void)mainScrollRefresh {
    _friendView.pageing = 1;
    [_friendView pullData:YES];
    _voiceView.pageing = 1;
    [_voiceView pullData:YES];
}
-(void)mainScrollEndfresh {
    [_mainScrollView.mj_header endRefreshing];
}

MainScrollview代理方法中的实现

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{

    //MainScrollview不需要刷新这里可不做处理
    if (scrollView == _mainScrollview){
        
        if (scrollView.contentOffset.y <= 0) {
            _mainScrollview.bounces = YES;
            subCollectionView.bounces = NO;
            
        }else{
            _mainScrollview.bounces = NO;
            subCollectionView.bounces = YES;
        }
    }
    
    CGFloat bottomCellOffset = tableHeaderView.height-40;//这里高度设置为头部视图高度即可
    if (scrollView.contentOffset.y >= bottomCellOffset) {
        scrollView.contentOffset = CGPointMake(0, bottomCellOffset);
        if (_canScroll) {
            _canScroll = NO;
            subCollectionView.canScroll = YES;
        }
    }else{
        if (!_canScroll) {//子视图没到顶部
            scrollView.contentOffset = CGPointMake(0, bottomCellOffset);
        }
    }
    _mainScrollview.showsVerticalScrollIndicator = _canScroll?YES:NO;
    
}
- (void)changeScrollStatus {
    _canScroll = YES;
    // 重要:子视图一定是canScroll = NO
    subCollectionView.canScroll = NO;
}

子类subCollectionView

/// 嵌套滚动代理
@protocol MutElementScrollDelegate <NSObject>
-(void)changeScrollStatus;
@end
// 子视图属性
@property(nonatomic,assign)BOOL canScroll;
@property(nonatomic,assign)BOOL subBounces;
@property(nonatomic,weak)id <MutElementScrollDelegate>delegate;
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    
    if (!_canScroll) {
        scrollView.contentOffset = CGPointZero;
    }
    if (scrollView.contentOffset.y <= 0) {
        
        _canScroll = NO;
        scrollView.contentOffset = CGPointZero;
        //这里就是通知父类改变父类的canScroll属性
        if (_delegate && [_delegate respondsToSelector:@selector(changeScrollStatus)]) {
            [_delegate changeScrollStatus];
        }
    }
    _subCollectionView.showsVerticalScrollIndicator = _canScroll?YES:NO;
}
// bounces
- (void)setSubBounces:(BOOL)subBounces {
    _subBounces = subBounces;
    _tableView.bounces = _subBounces;
}

仿支付宝首页刷新【tableview刷新】

参考链接

完整代码

#import "TBRefreshVC.h"

#import <MJRefresh.h>

#define KScreenWidth  [UIScreen mainScreen].bounds.size.width
#define KScreenHeight [UIScreen mainScreen].bounds.size.height
#define KTopViewHeight  300
#define KTopHeaderViewHeight  80

@interface TBRefreshVC ()<UITableViewDelegate,UITableViewDataSource>

@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIView *topView;
@property (nonatomic, strong) UIView *navBGView;
@property (nonatomic, strong) UIView *navView;
@property (nonatomic, strong) UIView *navNewView;
@property (nonatomic, strong) UIView *topHeaderView;
@property (nonatomic, assign) NSInteger dataCount;

@end

@implementation TBRefreshVC

- (void)dealloc {
    [self removeObserver:self forKeyPath:@"contentSize"];
}
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.navigationController.navigationBar.hidden = YES;
    
    [self.view addSubview:self.navBGView];
    [self.view addSubview:self.navView];
    [self.view addSubview:self.navNewView];
    [self.view addSubview:self.scrollView];
    [self.scrollView addSubview:self.topView];
    [self.scrollView addSubview:self.tableView];
    //添加刷新控件
    __weak TBRefreshVC *weakSelf = self;
    self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf.tableView.mj_header endRefreshing];
            weakSelf.dataCount += 5;
            [weakSelf.tableView reloadData];
        });
    }];
    
    self.scrollView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf.scrollView.mj_footer endRefreshing];
            weakSelf.dataCount += 5;
            [weakSelf.tableView reloadData];
        });
    }];
    
    
    [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
    self.dataCount = 20;
}
//根据tableView的contentSize改变scrollView的contentSize大小
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"contentSize"]) {
        CGRect tFrame = self.tableView.frame;
        tFrame.size.height = self.tableView.contentSize.height;
        self.tableView.frame = tFrame;
        self.scrollView.contentSize = CGSizeMake(0, self.tableView.contentSize.height+KTopViewHeight);
    }
}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat offsetY = self.scrollView.contentOffset.y;
    if (offsetY <= 0.0) {
        CGRect frame = self.topView.frame;
        frame.origin.y = offsetY;
        self.topView.frame = frame;
        CGRect tFrame = self.tableView.frame;
        tFrame.origin.y = offsetY + KTopViewHeight;
        self.tableView.frame = tFrame;
        if (![self.tableView.mj_header isRefreshing]) {
            self.tableView.contentOffset = CGPointMake(0, offsetY);
        }
    } else if (offsetY < KTopHeaderViewHeight && offsetY >0) {
        CGFloat alpha =  (offsetY*2/KTopHeaderViewHeight>0) ? offsetY*2/KTopHeaderViewHeight:0;
        if (alpha > 0.5) {
            self.navNewView.alpha = alpha*2-1;
            self.navView.alpha = 0;
        } else {
            self.navNewView.alpha = 0;
            self.navView.alpha = 1-alpha*2;
        }
        self.topHeaderView.alpha = 1-alpha;
    }
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    CGFloat offsetY = self.scrollView.contentOffset.y;
    if (offsetY < - 60) {
        [self.tableView.mj_header beginRefreshing];
    }
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataCount;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CELL"];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%d",(int)indexPath.row];
    return cell;
}
#pragma mark - getter && setter
- (UIScrollView *)scrollView {
    if (_scrollView == nil) {
        _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64, KScreenWidth, KScreenHeight-64)];
        _scrollView.delegate = self;
        //Indicator的显示位置
        _scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(KTopViewHeight, 0, 0, 0);
        _scrollView.contentSize = CGSizeMake(0, KScreenHeight*2);
    }
    return _scrollView;
}
- (UITableView *)tableView {
    if (_tableView == nil) {
        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, KTopViewHeight, KScreenWidth, KScreenHeight*2-KTopViewHeight)];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        _tableView.scrollEnabled = NO;
    }
    return _tableView;
}
- (UIView *)topView {
    if (_topView == nil) {
        _topView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KTopViewHeight)];
        _topView.backgroundColor = UIColor.grayColor;
        
        UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KTopHeaderViewHeight)];
        headerView.backgroundColor = UIColor.blackColor;
        for (int i = 0; i<4; i++) {
            UIButton *button = [[UIButton alloc] init];
            [button setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d",i+1]] forState:UIControlStateNormal];
            [headerView addSubview:button];
            button.frame = CGRectMake((KScreenWidth/4)*i, 0, KScreenWidth/4, KTopHeaderViewHeight);
        }
        self.topHeaderView = headerView;
        [_topView addSubview:headerView];
        UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, KTopHeaderViewHeight, KScreenWidth, KTopViewHeight-KTopHeaderViewHeight)];
        view.backgroundColor = [UIColor systemPinkColor];
        [_topView addSubview:view];
    }
    return _topView;
}
- (UIView *)navBGView {
    if (_navBGView == nil) {
        _navBGView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, 64)];
        _navBGView.backgroundColor = UIColor.yellowColor;
    }
    return _navBGView;
}
- (UIView *)navView {
    if (_navView == nil) {
        _navView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, 64)];
        _navView.backgroundColor = [UIColor clearColor];
        UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(10, 20, 200, 44)];
        searchBar.backgroundImage = [[UIImage alloc] init];
        UITextField *searchField = [searchBar valueForKey:@"searchField"];
        if (searchField) {
            [searchField setBackgroundColor:[UIColor colorWithRed:230/255 green:230/250 blue:230/250 alpha:0.1]];
        }
        [_navView addSubview:searchBar];
        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(220, 20, 44, 44)];
        [button setImage:[UIImage imageNamed:@"contacts"] forState:UIControlStateNormal];
        [_navView addSubview:button];
    }
    return _navView;
}
- (UIView *)navNewView {
    if (_navNewView == nil) {
        _navNewView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, 64)];
        _navNewView.backgroundColor = [UIColor clearColor];
        UIButton *cameraBtn = [[UIButton alloc] initWithFrame:CGRectMake(10, 20, 44, 44)];
        [cameraBtn setImage:[UIImage imageNamed:@"nav_camera"] forState:UIControlStateNormal];
        cameraBtn.backgroundColor = UIColor.redColor;
        [_navNewView addSubview:cameraBtn];
        UIButton *payBtn = [[UIButton alloc] initWithFrame:CGRectMake(64, 20, 44, 44)];
        [payBtn setImage:[UIImage imageNamed:@"nav_pay"] forState:UIControlStateNormal];
        payBtn.backgroundColor = UIColor.greenColor;
        [_navNewView addSubview:payBtn];
        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(118, 20, 44, 44)];
        [button setImage:[UIImage imageNamed:@"nav_scan"] forState:UIControlStateNormal];
        button.backgroundColor = UIColor.blueColor;
        [_navNewView addSubview:button];
        _navNewView.alpha = 0;
    }
    return _navNewView;
}

@end