iOS UITableView+UICollectionView嵌套,手势冲突解决

首先,新的一年,怀有期待的努力着!这两个月,昼夜不分. 看着自己写的代码,才意识到日子是切切实实的过了的.
这个主题我很早很早就想写的. 然后就没有然后了. 这次开发中正好有这个需求,那当然是不能再错过的. 主要记录实现的原理以及遇到的问题和解决方案.

1. 页面展示

定义:

  • MainTableView: 就是用户看到的滚动视图,mainTableView的父视图就是self.view.
  • ContentTableViewCell:就是tableView的cell,和普通的自定义cell一样.这个里面放的就是我们的HeaderView,当然你也可以用tableHeaderView来实现.Cell有一个好处就是自适应内容的高度,并且很容易的取到这个高度.
  • ContentView:这个是ContentTableViewCell的真实的ContentView,这就是一个简单的UIView,但里面的子视图是一个UICollectionView.
  • TitleView:这就是items的View,这里把这个View作为TableView的sectionHeaderView来实现.
  • ContentCollectionView:最上层用来展示数据的collectionView,根据需求用collectionView还是tableView,一般来说都是一个列表.

相信写到这里,你已经知道了大概的实现原理了吧. 实现的最终效果如下.


output.gif

2. 实现思路

实现这个页面,最重要的问题是要解决手势冲突.监听MainTableView和contentCollectionView的滚动方法来控制彼此的ContentOffset. MainTableView和contentCollectionView之间的通信有多种方式.通知或者代理.这里采用的是代理的方法,用代理,在同一个VC里实现滚动的监听,看起来更清楚一些.

2.1 实现下面方法满足同时监听多个相同手势

相同类型的手势,同一时间只有一个能够得到辨认.下面这个方法返回Yes也就意味着所有相同类型的手势都能得到处理.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

2.2 MainTableView的滚动监听

临界点就是需要悬停的位置.也就是HeaderView刚好消失的位置.这里用的Cell,就可以直接用 bottomCellOffset = [_contentTableView rectForSection:1].origin.y取到Header的高度.如果bottomCellOffset > offSetY,说明到了顶处,这个时候就固定MainTableView的contentOffSet,让MainTableView保持不动.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {   
    CGFloat bottomCellOffset = [_contentTableView rectForSection:1].origin.y;
    if (self.currentScrollingListView != nil && self.currentScrollingListView.contentOffset.y > 0) {
        //mainTableView的header已经滚动不见,开始滚动某一个listView,那么固定mainTableView的contentOffset,让其不动.
        _contentTableView.contentOffset = CGPointMake(0, bottomCellOffset);
    }
    //mainTableView已经显示了header,listView的contentOffset需要重置.
    if (scrollView.contentOffset.y < bottomCellOffset) {
        if(_currentScrollingListView.contentOffset.y > 0) {
            _currentScrollingListView.contentOffset = CGPointZero;
        }
    }
}

2.3 contentCollectionView的滚动监听

这里用的是代理.所以这个方法也是在MainViewController里.记录当前滚动的ListView.通过与lastScrollingListViewContentOffsetY的比较可以判断contentCollectionView是向上滚动,还是向下滚动.这里有一个问题:需要设置MainTableView的bouces = NO,如果没有设置这个的话,那么_contentTableView.contentOffset.y == 0几乎就不会执行.但是这个设置为NO的同时也会引发另一个问题,这个在下面的问题中列出.

其实简单的说就是以HeaderView的高度为临界点,在HeaderView消失之前,就让MainTableView滚动,而让contentCollectionView固定不动.反之,就让contentCollectionView滚动,MainTableView固定不动.

- (void)contentCollectionViewDidScroll:(UICollectionView *)contentCollectionView
{
    self.currentScrollingListView = contentCollectionView;
    
    CGFloat bottomCellOffset = [_contentTableView rectForSection:1].origin.y;
    BOOL shouldProcess = YES;
    
    if (contentCollectionView.contentOffset.y > self.lastScrollingListViewContentOffsetY) {
    }
    else {
        if(_contentTableView.contentOffset.y == 0) shouldProcess = NO;
        else {
            if(_contentTableView.contentOffset.y < bottomCellOffset) {
                _currentScrollingListView.contentOffset = CGPointZero;
            }
        }
    }
    if (shouldProcess) {
        if (_contentTableView.contentOffset.y < bottomCellOffset) {
            if (_currentScrollingListView.contentOffset.y > 0) {
                _currentScrollingListView.contentOffset = CGPointZero;
            }
        }
        else {
            _contentTableView.contentOffset = CGPointMake(0, bottomCellOffset);
        }
    }
    self.lastScrollingListViewContentOffsetY = self.currentScrollingListView.contentOffset.y;  
}

另外,关于CollectionView的定点问题.有时间我再整理一下.

[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:contentViewCurrentIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];

3. 一些问题和解决方案

3.1 当contentCollectionView没有数据源时,滚动到悬停位置后无法滑动到原来的状态?

当列表没有数据时就检测不到滑动手势。可以根据需要,或者在网络请求的回调中做判断,如果没有数据或者网络请求失败等情况添加contentCollectionView的noDataView.

3.2 上滑之后会出现第一次点击cell不响应点击事件???

初始化tableView的时候添加以下代码.cancelsTouchesInView设置为NO,当两个事件有冲突时,都会响应两个事件.所以这个设置为NO可以解决很多的问题.

_contentTableView.panGestureRecognizer.cancelsTouchesInView = NO; 

3.3 如何动态显示titleView item的个数?

这个在网络请求回调中初始化TitleArray就可以了.这个有什么问题呢?

3.4 关于刷新?

其实还是上面关于临界点的问题.如何做到下拉的时候MainTableView固定不动,而contentCollectionView可以滚动.所以这个地方,就必须要设置MainTableView的bonces.上面的代码就已经可以实现了.

3.5 mainTableView.bounces = NO;设置后滚动到一定位置后无法滚动?

一般我们都是通过懒加载的方式去创建控件,如果在这个时候去设置frame,那么这个frame一经设置是不会改变的.所以需要在下面这个方法里面设置tableView的frame.viewDidLayoutSubviews方法是当Controller的子视图的positon和frame发生改变时会被调用.也就是执行完AutoLayout后会调用这个方法.

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.contentTableView.frame = self.view.bounds;
}

3.6 滚动的时候,会重新调用viewDidLoad方法?(这个是网上的一个Demo,之前我也有参考)

如果你也遇到同样的问题. 试试不要用懒加载的方式去创建MainTableView.这里的问题是因为在监听滚动的时候,vc.contentCollectionView.contentOffset会导致subView被添加到self.view上从而引发了viewDidLoad方法的调用.具体的原因还需要深度剖析.但不通过懒加载可以解决这个问题.

    for (id  vc in _viewControllers) {
            vc.vcCanScroll = cellCanScroll;
            if (!cellCanScroll) {
                vc.contentCollectionView.contentOffset = CGPointZero;
            }
        }

4. 巨人的肩膀

嵌套滚动参考一
嵌套滚动参考二

5. 总结

以上,就是关于tableView的嵌套使用.基本上遇到的问题我都列出来了,后续如果我再发现其它的问题也会补上,最近有不少想要总结的点,但真的太忙了,一有时间就会更新的。终于完成了这一篇博客!2019!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容