效果图
实现原理
外层一个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 && self.type == SpecialTableViewTypeSub) {
[self setContentOffset:CGPointZero];
self.canScroll = NO;
self.forceCanScroll = NO;
}
}
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
使用方法
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;
}
如果对你有帮助,欢迎star
原文地址:https://blog.csdn.net/LIUXIAOXIAOBO/article/details/127341358
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_24160.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。