美文网首页iOS进阶+实战设计iOS学习
获取CollectionViewCell的indexPath

获取CollectionViewCell的indexPath

作者: CoderAO | 来源:发表于2015-09-04 18:10 被阅读23935次

最近大半个月的时间一直忙于编写一个不大但是也不算简单的小项目, 更新博客的频率低了好多. 今天发现并解决了一个问题, 由于查找解决问题的途中发现很少人遇到这个问题, 觉得拿出来说说, 说不定会给以后遇到的人带来一些便利.

首先, 页面的需求是这样的:

1.页面上半部分是可以横向分页滚动的视图A, 每页显示一个图表
2.随着视图A滚动到不同的页数, 下半部分(视图B)变换不同的数据
3.视图A每页的图表有多处可以点击,并且点击事件也会触发视图B数据显示的变换.
用图来表示一下:


页面要求
整体的思路并不难, 我采取了下面的方案:

1.顶部使用UICollectionView作为滚动视图, 使其cell大小等于自身大小, 每个cell展示一个图表
2.每次滚动完毕及点击cell中图表的点时, 获取collectionView当前展示的cell的indexPath,以此获取该坐标对应的值展示到下方.

所以,这个功能的关键点就在于如何获取顶部CollectionView当前显示的cell的indexPath.

我先后试过以下几种方案:

方案一:

通过之前做过的自动轮播的广告banner的经验(和这个需求有相似的地方),我先采用了之前的方法:
通过UICollectionView的-collectionView:didEndDisplayingCell:forItemAtIndexPath:方法得到indexPath更新的时刻, 然后用[collectionView indexPathsForVisibleItems]获取一组当前显示的cell们的indexPath的数组,由于我的cell大小刚好等于collectionView的大小,所以这个数组只包含一个元素(后来证明了即使是这样,这个数组也不一定只有一个元素),我只要取里面的第一个就好了.

- (void)collectionView:(UICollectionView *)collectionView
  didEndDisplayingCell:(UICollectionViewCell *)cell
    forItemAtIndexPath:(NSIndexPath *)indexPath {
    // 获取当前显示的cell的下标
    NSIndexPath *firstIndexPath = [[self.collectionView indexPathsForVisibleItems] firstObject];
    // 赋值给记录当前坐标的变量
    self.currentIndexPath = indexPathNow;
    // 更新底部的数据 
    // ...
}

这个方案对于此页面本身基本可以达到要求,但是由于下级页面可能会修改到这个页面的元素,导致cell个数增加或者减小, 有些情况下回到此页面时会造成程序崩溃.
打个比方: 我的collectionView的cell共有3个,并且将cell滑动到最后一页(最后一个cell),此时记录当前的下标为2. 下级页面删除了一个元素,再回到此页面的时候,didEndDisplay...方法会最先被调用,这个方法里面会取数据重新设置下半部分视图的显示, 而此时当前的下标仍为2, 数据只剩两个了,就导致了应用的崩溃.

如果从子页面回来didEndDisplay...方法不被调用或者比较后面被调用,就不会出现这种情况,但是这个方法的调用时机岂是我等可以控制的? 于是乎换了一个方案.

方案二:

通过UIScrollView的-scrollViewDidEndDecelerating:方法得到indexPath更新的时刻, 然后用[collectionView indexPathsForVisibleItems]获取一组当前显示的cell们的indexPath的数组,和上面的方案一样,我只要取里面的第一个.

didEndDecelerating是在scrollView(collectionView)减速完成(滚动停止)的时刻调用的,由于又是pageEnabled == YES, 这个时刻只有一个cell在屏幕上.而且didEndDecelerating不会在从子页面返回的时候调用,也就解决了方案一的问题.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    // 获取当前显示的cell的下标
    NSIndexPath *firstIndexPath = [[self.collectionView indexPathsForVisibleItems] firstObject];
    // 赋值给记录当前坐标的变量
    self.currentIndexPath = indexPathNow;
    // 更新底部的数据 
    // ...
}

我曾以为问题就这样解决了,结果意外地发现, 有些时候我点击cell中图表的某个点时,cell会跳变为隔壁的cell,查了良久,才发现就是由于对collectionView当前的坐标获取不准确导致的, 进一步地发现,这个不准确就是由于:即使我的cell大小等于collectionView的大小,在[collectionView indexPathsForVisibleItems]方法得到的数组数据也有可能大于一个.并且顺序还不一定,导致我也不能通过firstObject或者lastObject来获取我想要的值(我也不知道为什么会大于一个还有不确定的顺序).

方案三:

再后来,我找到了这个方法:indexPathForItemAtPoint:---根据某一点得到位于这点上的cell的坐标,而且返回值是一个确定的indexPath,而不是数组,正合我意.需要注意的是,这个方法传入的参数point是以scrollView的contentView为坐标系的坐标,使用之前要先进行一次转换.最终我的做法是这样:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    // 将collectionView在控制器view的中心点转化成collectionView上的坐标
    CGPoint pInView = [self.view convertPoint:self.collectionView.center toView:self.collectionView];
    // 获取这一点的indexPath
    NSIndexPath *indexPathNow = [self.collectionView indexPathForItemAtPoint:pInView];
    // 赋值给记录当前坐标的变量
    self.currentIndexPath = indexPathNow;
    // 更新底部的数据 
    // ...
}

问题解决了.

相关文章

网友评论

  • 爱恨的潮汐:大佬,这方法牛逼
  • 86dd336b7a56:为什么方案三获取到的indexPathNow一直是nil呢,pInView是有值的,而且也是正确的,但是indexpath一直是nil
  • Waisti:👏
  • 进击的小恶魔:方案二的"我也不知道为什么会大于一个还有不确定的顺序"是因为cell重用, 用Debug View Hierarchy, 可以查看到界面之外隐藏的cell , 结合打印的indexPath, 就可以理解了. 楼主的思路受教了, 感谢!
  • 心语风尚:在collctionview中cell宽度对于屏幕宽度 是左右滑动的 在cellforitem方法中输出indexpath.row为什么运行后首次输出是0手动滚动到第二个单元格一次性输出1、2滚动到第三个单元格输出0 为什么不是依次输出0、1、2、3 tableview的cellforrow输出貌似是连续的0、1、2、3
    心语风尚:@有故事的前进者 看了相关 类似需求 没有通过 滑动 获取 都是通过偏移 计算的
    心语风尚:@有故事的前进者 知道原因了 在cellforrow获取的indexpath 打印是不正确的 因为单元格复用 当滑到下一个单元格 并不会按顺序输出也可能不输出 因为复用了单元格 array「indexpath.row」这样取值是正确的是因为复用原因不会每次滚动都取值所以是顺序值 想获取 正确indexpath 在外部 scroll滚动代理方法根据偏移 算index
    captainGao:这个问题的原因你找到了吗 我也遇到同样的问题
  • FleetingYears:楼主:求QQ啊,为什么我用你的第三个方法返回的是nil啊。求解、很急,纠结好几天了这个问题。
  • 楚简约:怎么获取indexpath 中path前面那个数字, {length = 2, path = 3 - 0} item= 0 row = 0
  • e7fd345f5560:哥们儿我只能说真**NB,我纠结这个问题半天了。一直以为苹果出的这个方法是不会出问题的呢。坑死我了,给你一个大大的👍
  • yep灬:666
  • YungFan:精益求精:+1:
  • BigBowen:刚好遇到这个问题,谢谢!
  • 码代码的李二狗:哎 早点看见你的文章就好了
  • 44da12571338:谢谢,顺利解决问题
  • Stone未来我来:写的很详细 :+1:
  • Raybon_lee:你获取过指定的headerView me
  • 9bfe700d122a:求你了 加我,绝对不打扰你。 :pray:
    超_iOS:@金鲤 @我干嘛
    金鲤:@_超 你这难道不算是打扰,:interrobang:
    超_iOS:@不吐葡萄皮z 哥们你有啥诉求吗?
  • 9bfe700d122a:Enjoy your coding! :kissing_closed_eyes:

本文标题:获取CollectionViewCell的indexPath

本文链接:https://www.haomeiwen.com/subject/hmilcttx.html