iOS UITableView的嵌套和sectionHeaderView悬停的解决方案

来源:互联网 发布:java提取方法中的泛型 编辑:程序博客网 时间:2024/06/07 18:42

应用情景

情景一:

情景一

说明:是不是和tableView的Plain类型一样,其实这个是由两个列表实现的

情景二:

情况二

说明:此时,就可以发现和普通的列表有些不一样了

情景三:

情景三

说明:笔者最初就是为了实现这种情况,由于项目需求,需要防QQ空间,不同的是需要类型的切换,当时没想到好的解决方案,最后受同事启发,在其demo上进行修改,使得tableView可以满足大部分的悬停需求


思路说明

1、由于是两个tableView嵌套实现,所以首要就是兼容手势,使得我们的拖拽手势可以向下传递

2、通过改变列表的contentOffset来让列表是否”滚动”

3、子列表默认不滚动,当父列表滚动到需要悬停的位置时,父列表”停止”滚动,子列表开始滚动

4、当子列表下拉,contentOffset.y小于0时,子列表”停止滚动”,父列表开始”滚动”

5、使用通知来接收滚动消息


主要实现过程(代码)

首先继承UITableView新建LolitaTableView类,并定义两种类型

typedef NS_ENUM(NSInteger , LolitaTableViewType) {    LolitaTableViewTypeMain,  // 父列表    LolitaTableViewTypeSub    // 子列表};

1、兼容手势

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{    if (self.type==LolitaTableViewTypeMain) {   // 父table类型需要兼容手势        return YES;    }    return NO;}

2、注册通知

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollStop:) name:kScrollStopNotificationName object:nil];

3、重写setContentOffset方法

- (void)setContentOffset:(CGPoint)contentOffset{    [super setContentOffset:contentOffset];    CGFloat y = contentOffset.y;    if(self.type == LolitaTableViewTypeMain){   // main类型        CGFloat stayPosition = self.tableHeaderView.frame.size.height;  // 默认停留的位置        if ([self.delegate_StayPosition respondsToSelector:@selector(lolitaTableViewHeightForStayPosition:)]) {            stayPosition = [self.delegate_StayPosition lolitaTableViewHeightForStayPosition: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正常滚动                [super setContentOffset:contentOffset];            }        }else{ // main禁止滚动            contentOffset.y = stayPosition;            [super setContentOffset:contentOffset];        }    }else if(self.type == LolitaTableViewTypeSub){ // sub类型        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正常滚动                [super setContentOffset:contentOffset];            }        }else{ // sub禁止滚动            contentOffset.y = 0;            [super setContentOffset:contentOffset];        }    }else{        [super setContentOffset:contentOffset];    }}

4、通知处理

- (void)scrollStop:(NSNotification *)notification{    LolitaTableView *table = notification.object;    // 把其他所有的sub都移动到顶部    if (table.type == LolitaTableViewTypeSub && self.type == LolitaTableViewTypeSub) {        [self setContentOffset:CGPointZero];    }    if(self != table){  // 发送通知的table和当前self不是同一个时,则需要滚动        self.canScroll = YES;    }}

使用

1、父类tableView

@property (strong ,nonatomic) LolitaTableView *mainTable;// 初始化父类列表-(LolitaTableView *)mainTable{    if (_mainTable==nil) {        _mainTable = [[LolitaTableView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-64) style:UITableViewStyleGrouped];        _mainTable.delegate = self;        _mainTable.dataSource = self;        _mainTable.delegate_StayPosition = self;  // 悬停代理        _mainTable.tableFooterView = [UIView new];        _mainTable.showsVerticalScrollIndicator = NO;        _mainTable.type = LolitaTableViewTypeMain; // 列表类型    }    return _mainTable;}注:需要将子列表加到列表上,最好是最后一个section的cell上,这样比较灵活;其他位置也可以添加,主要是需要配合悬停的位置使用// 实现悬停代理// !!!: 悬停的位置-(CGFloat)lolitaTableViewHeightForStayPosition:(LolitaTableView *)tableView{    // 悬停在第3个secion.y处    return [tableView rectForSection:2].origin.y;}

2、子类列表

-(LolitaTableView *)table{    if (_table==nil) {        _table = [[LolitaTableView alloc] initWithFrame:CGRectZero];        _table.delegate = self;        _table.dataSource = self;        _table.showsVerticalScrollIndicator = NO;        _table.tableFooterView = [UIView new];        _table.type = LolitaTableViewTypeSub; // 除了类型要设置为子类,用法和系统类型一样    }    return _table;}

Demo地址

阅读全文
0 0
原创粉丝点击