iOS scrollView嵌套tableView的手势冲突解决
在平时项目中,我们经常会碰到类似UIScrollView
嵌套UITableView
的需求,虽然苹果并不建议这种做法,但是这样的需求在平时工作中还是很常见的。比如笔者公司项目之前用到的地方:
可以看到最上面是一块轮播图组件,我也已经整理了一份轮播图组件在github上面,轮播图下面还有若干条其他的内容,而且这几块内容都是后台动态控制显示的,所以这里用UIScrollView
设置顶部偏移量实现是很不方便的。最外层我肯定选择使用tableView
分区管理来实现。而下面的横向分类页面肯定需要tableView
去实现
这样的话问题就来了,先不说下面的横向分页如何实现,这个页面必定需要在一个tableView
中嵌套多个不同的tableView
,但是如果嵌套了其他的scrollView
,就需要我们判断不同条件下让哪个scrollView
响应滑动事件,因此这里我们需要解决的就是手势的冲突问题。
最开始想到的是在滑动tableView
时候根据偏移量设置scrollEnabled
来控制两个tableView
的响应,但是会有个问题就是当滚动到顶部时用户必须第二次滑动才可以显示出外层的tableView
,这样就会造成一个卡顿的效果,所以这个方法是行不通的。
下面说一下我的解决思路:
这里就直接分为mainTableView
和subTableView
,设置mainTableView
的联动手势UIGestureRecognizer
/**
同时识别多个手势
@param gestureRecognizer gestureRecognizer description
@param otherGestureRecognizer otherGestureRecognizer description
@return return value description
*/
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
下面的分类pageView
是直接使用了封装的page框架FSScrollContentView,在mainTableView
的UIScrollViewDelegate
方法内判断mainTableView
的偏移量,当标题栏滚动到顶部的时候固定mainTableView
的偏移量
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat bottomCellOffset = [_tableView rectForSection:1].origin.y - 64;
if (scrollView.contentOffset.y >= bottomCellOffset) {
scrollView.contentOffset = CGPointMake(0, bottomCellOffset);
if (self.canScroll) {
self.canScroll = NO;
self.contentCell.cellCanScroll = YES;
}
}else{
if (!self.canScroll) {//子视图没到顶部
scrollView.contentOffset = CGPointMake(0, bottomCellOffset);
}
}
self.tableView.showsVerticalScrollIndicator = _canScroll?YES:NO;
}
上面代码中的canScroll
是定义的一个BOOL
变量用来控制mainTableView
的偏移量
此时,subTableView
收到可以滚动的信号cellCanScroll
,才开始响应滑动的手势,在subTableView
的UIScrollViewDelegate
方法内实现:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (!self.vcCanScroll) {
scrollView.contentOffset = CGPointZero;
}
if (scrollView.contentOffset.y <= 0) {
if (!self.fingerIsTouch) {
return;
}
self.vcCanScroll = NO;
scrollView.contentOffset = CGPointZero;
[[NSNotificationCenter defaultCenter] postNotificationName:@"leaveTop" object:nil];//到顶通知父视图改变状态
}
self.tableView.showsVerticalScrollIndicator = _vcCanScroll?YES:NO;
}
其实到这里会发现主要是通过设置两个scrollView
的偏移量来解决这个手势冲突的问题。因为代码已经表达的很清楚,不太擅长表达,这里只是大概描述一下使用场景。
具体的实现方式已经写成了一个demo,里面也有详细的注释,可以前去下载:FSScrollViewNestTableView
2017.6.21--应网友要求,demo添加了刷新逻辑
给大家看一下实现后的效果图:
FSScrollViewNestTableView.gif