iOS scrollView嵌套tableView的手势冲突解决方案
https://www.jianshu.com/p/8bf6c2953da3?t=123
在平时项目中,我们经常会碰到类似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添加了刷新逻辑
给大家看一下实现后的效果图:

这里只是提供了一种解决方案,欢迎提出问题多多交流
作者:PURE蓝胖子
链接:https://www.jianshu.com/p/8bf6c2953da3
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具