效果图

在这里插入图片描述

实现原理

外层一个tableview,内层一个tableView
设置一个滚动临界点,超过这个临界点之后
只允许一个某个tableView 滚动。该逻辑在自定义tableView 内部实现

核心代码

.h


typedef NS_ENUM(NSInteger , SpecialTableViewType) {
    SpecialTableViewTypeMain,
    SpecialTableViewTypeSub
};

@protocol LBNestScrollTableViewDelegate;

NS_ASSUME_NONNULL_BEGIN

static NSString *const kScrollStopNotificationName = @"scrollStop"; // 滚动停止通知

@interface LBNestScrollTableView : UITableView

@property (assign, nonatomic) SpecialTableViewType type;
@property (assign, nonatomic) BOOL forceCanScroll;
@property (assign, nonatomic) BOOL canScroll;

@property (nonatomic,weak) id <LBNestScrollTableViewDelegate> delegate_StayPosition;

@end

@protocol LBNestScrollTableViewDelegate <NSObject>

@required
-(CGFloat)nestTableViewHeightForStayPosition:(LBNestScrollTableView *)tableView;// 悬停的位置

@end

.m


@implementation LBNestScrollTableView

- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style{
    self = [super initWithFrame:frame style:style];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollStop:) name:kScrollStopNotificationName object:nil];
        self.canScroll = YES;
        self.showsVerticalScrollIndicator = NO;
        self.separatorStyle = UITableViewCellSeparatorStyleNone;
    }
    return self;
}


-(void)setType:(SpecialTableViewType)type{
    _type = type;
    self.canScroll = type==SpecialTableViewTypeSub?NO:YES;   // 子table默认不可滚动
}

//外层tableView 需要同时支持多个手势
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    if (self.type==SpecialTableViewTypeMain) {   // 主table类型需要兼容手势
        return YES;
    }
    return NO;
}

/*
主要逻辑就在该方法里,刚开始的时候
只允许外层tableView滚动,过了临界点之后,
只允许内层tableView 滚动
*/
- (void)setContentOffset:(CGPoint)contentOffset{
    CGFloat y = contentOffset.y;
    [super  setContentOffset:contentOffset];
    if(self.type == SpecialTableViewTypeMain){   // main类型
        CGFloat stayPosition = self.tableHeaderView.frame.size.height;  // 默认停留的位置
        if ([self.delegate_StayPosition respondsToSelector:@selector(nestTableViewHeightForStayPosition:)]) {
            stayPosition = [self.delegate_StayPosition nestTableViewHeightForStayPosition:self];  // 获取到停留的位置
        }
        if(self.canScroll == YES){
            if(y > stayPosition){
                contentOffset.y = stayPosition;
                [super setContentOffset:contentOffset];
                self.canScroll = NO;
                // 发送通知,主类不可滚动
                [[NSNotificationCenter defaultCenter] postNotificationName:kScrollStopNotificationName object:self userInfo:nil];
            }
        }else{ // main禁止滚动
            contentOffset.y = stayPosition;
            [super setContentOffset:contentOffset];
        }
    }else if(self.type == SpecialTableViewTypeSub){ // sub类型
        if (self.forceCanScroll) {
            if(y < 0){
                contentOffset.y = 0;
                [super setContentOffset:contentOffset];
                // 发送通知子类不可滚动
                [[NSNotificationCenter defaultCenter] postNotificationName:kScrollStopNotificationName object:self userInfo:nil];
            }
        }else {
            if(self.canScroll == YES){
                if(y < 0){
                    contentOffset.y = 0;
                    [super setContentOffset:contentOffset];
                    self.canScroll = NO;
                    // 发送通知子类不可滚动
                    [[NSNotificationCenter defaultCenter] postNotificationName:kScrollStopNotificationName object:self userInfo:nil];
                }
            }else{ // sub禁止滚动
                contentOffset.y = 0;
                [super setContentOffset:contentOffset];
            }
        }
    }
}
- (void)scrollStop:(NSNotification *)notification{
    LBNestScrollTableView *table = notification.object;
    if(self != table){  // 发送通知的table和当前self不是同一个时,则需要滚动
        self.canScroll = YES;
    }
    // 把其他所有的sub都移动顶部,除去主的,其他table皆不能滚动
    if (table.type == SpecialTableViewTypeSub &amp;&amp; self.type == SpecialTableViewTypeSub) {
        [self setContentOffset:CGPointZero];
        self.canScroll = NO;
        self.forceCanScroll = NO;
    }
}

-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

使用方法

podfile

source 'https://gitee.com/liuboliu/lxbrolling-view-spec.git'
...
pod 'LBNestTableView'

//外层大tableView
- (LBNestScrollTableView *)tableView
{
    if (!_tableView) {
        _tableView = [[LBNestScrollTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
        [_tableView registerClass:[TabTableCell class] forCellReuseIdentifier:NSStringFromClass([TabTableCell class])];
        [_tableView registerClass:[HeaderCell class] forCellReuseIdentifier:NSStringFromClass([HeaderCell class])];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        // 通过代理获取头部高度
        _tableView.delegate_StayPosition = self;
    }
    return _tableView;
}

//实现协议方法

#pragma mark - SpecialTableViewDelegate

//该方法返回外层tablView 可以滚动的最大偏移量
- (CGFloat)nestTableViewHeightForStayPosition:(LBNestScrollTableView *)tableView
{
    return 200;
}

//tableView 协议方法

pragma mark - UITableViewDelegate, UITableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.row == 0) {
        HeaderCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([HeaderCell class])];
        return cell;
    }
    TabTableCell  *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([TabTableCell class])];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.row == 0) {
        return 200;
    }
    return (CGRectGetHeight(self.view.frame) - 100);
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 2;
}

//内层tableView

- (LBNestScrollTableView *)tableView
{
    if (!_tableView) {
        _tableView = [[LBNestScrollTableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
        [_tableView registerClass:[ContentCell class] forCellReuseIdentifier:NSStringFromClass([ContentCell class])];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        _tableView.type = SpecialTableViewTypeSub;
    }
    return _tableView;
}

demo: link

如果对你有帮助,欢迎star

原文地址:https://blog.csdn.net/LIUXIAOXIAOBO/article/details/127341358

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_24160.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注