【问题标题】:Detect when UITableViewCell goes off the screen检测 UITableViewCell 何时离开屏幕
【发布时间】:2010-10-24 20:55:22
【问题描述】:

我正在使用自定义创建的 UITableViewCell 实现一个丰富的 UITableView,我以一种方式在屏幕上显示它们,但是一旦它们离开屏幕我想记下这一点,因为它们第二次出现我会喜欢他们以不同的方式展示。离开屏幕时认为自动“标记为已读”。

我一直在寻找一些方法来检测单元格何时离开屏幕(获取的释放或出列或等效),最好在 :UITableViewController 类中快速记录 [indexPath 行],但是在 :UITableViewCell 中同样出色。

我无法以任何标准方式做到这一点......计算它出现的次数似乎是不可能的,因为我在桌子上进行了多次 reloadData 调用。

有人有什么想法吗?这似乎有点棘手:)

【问题讨论】:

    标签: iphone uitableview


    【解决方案1】:

    我想我会尝试定期检查 UITableView 的 indexPathsForVisibleRows 属性。从最大的索引路径,你可以推断出之前的所有行都被滚动过去了。

    【讨论】:

    • 是的,这是一个选项,我可以将该调用放在 cellForRowAtIndexPath 中。但是我有可变高度行,因此这不能保证屏幕外单元格将被标记为屏幕外:|
    【解决方案2】:

    我认为你可以使用

    - (NSArray *)visibleCells
    

    你的 UITableView 的方法。这将返回一个包含所有可见单元格的数组。然后,您可以以您想要的方式标记任何“不可见”(即不在此数组中)的数据,这样当您滚动回它时,它已被更新。

    希望有帮助

    【讨论】:

      【解决方案3】:

      您确定要捕捉到屏幕外的单元格吗?如果您想将项目标记为已读,这似乎不是正确的方法。例如,我可能会非常快速地滚动表格,如果您将所有内容都标记为已读,我会感到非常惊讶。

      至于技术部分,只需保留屏幕上的单元格列表(cellForRowAtIndexPath 应将单元格添加到该列表中),并在 scrollViewDidScroll 委托方法中检查是否有任何单元格不再可见。

      另一个可能的想法:我记得单元格上有prepareForReuse 方法。不过,不确定何时调用它。

      【讨论】:

        【解决方案4】:

        Andrey Tarantsov 提到的 UITableViewCell 上的prepareForReuse 方法看起来不错。在其中放置几个​​ NSLog 可以让您打印出单元格的任何变量的值。关于如何将其设置回表格视图控制器的任何想法?

        【讨论】:

        • 我使用委托来做这件事
        【解决方案5】:

        一旦UITableViewCell 不可见,它将从UITableView 中删除。您可以覆盖方法-(void)removeFromSuperView,并在该方法中执行某些操作。最后别忘了拨打[super removeFromSuperView]

        【讨论】:

        • 这似乎不是一个可靠的解决方案。我刚刚在 iOS 6.0 模拟器上对此进行了测试,单元格似乎被设置为隐藏而不是被删除。奇怪的是,setHidden:YES 在我的实现中也没有被调用!显然在 tableView 实现中 ivar 是直接设置的,跳过了属性设置器方法。
        • 子类化 UITableViewCell 后不会调用 removeFromSuperView 方法
        【解决方案6】:

        这是一个老问题,但如果有人在看,在 iOS6 中,引入了一个新的 UITableViewDelegate 函数来执行此操作:

        - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
        

        它可以很好地告诉您何时删除单元格,但是,它非常彻底,因此如果您重新加载单元格,即使是被替换的旧单元格也会触发此委托功能。在我的实现中,我只是检查传递的indexPath 是否仍在数组tableView.indexPathsForVisibleRows 内。比如:

        - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
        {
            if ([tableView.indexPathsForVisibleRows indexOfObject:indexPath] == NSNotFound)
            {
                // This indeed is an indexPath no longer visible
                // Do something to this non-visible cell...
            }
        }
        

        【讨论】:

        • 这是我正在寻找的解决方案,但适用于 iOS 5.0。有什么建议吗?
        • 不幸的是,Apple 没有提供任何内容。我所做的是使用 scrollViewDidScroll 并进行快速计算,以查看 visibleCells 数组自滚动视图的上一个“帧”以来是否发生了变化,在这种情况下,我对现在丢失的单元格做一些事情。希望有帮助!
        • 遗憾的是 tableView.indexPathsForVisibleRows 直到在 didEndDisplayingCell 被调用之后才会更新,所以如果您添加将变得可见的新单元格,旧单元格将从显示中删除,但仍会在 tableView.indexPathsForVisibleRows 中。 (至少对于 iOS 7)。
        • @Olof_t 似乎确实如此,所以我刚刚针对我的 ios 7 应用程序对 tableView.indexPathsForVisibleRows 进行了检查。我还在相应的 willDisplayCell: 方法中添加了一些代码来处理一些极端情况。
        • 我用它来停止单元格内的视频播放,因为只要视频继续播放,didEndDisplayingCell 就不会被调用。
        【解决方案7】:

        我知道这是一个非常古老的问题,但如果有人正在寻找 Swift 5 的答案:

        func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            <#code#>
        }
        

        【讨论】:

          【解决方案8】:

          当单元格滚动出屏幕时,我需要从单元格中获取一些数据。我使用了@Mr.T's answer,但它没有说明如何获取数据。

          例如,我正在使用的单元类的名称是MyCell,其中有一个名为 MyModel 的数据模型,其属性为 postId。我最初在cellForItem 中设置了该信息:

          var datasource = [MyModel]()
          
          func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
              let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MyCell
          
              cell.myModel = datasource[indexPath.item] // an individual instance of MyModel from the array
          
              print("cellForItem - indexPath.item: ", indexPath.item) // if the was the very first cell coming on it would print 0
              print("postId: ", cell.myModel.postId) // maybe the postId is qwerty
          
              return
          }
          

          要在单元格滚出屏幕时从单元格中获取一些数据:

          func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
          
              guard let myCell = cell as? MyCell else { return } // You must cast the cell from the method param to your cell type which for me is MyCell
          
              print("didEndDisplayingCell - indexPath.item: ", indexPath.item) // if this was the very first cell scrolling off it should print 0
              print("postId: ", myCell.myModel.postId) // the postId should be qwerty
          }
          

          对此进行测试的最佳方法是向您的 collectionView 添加少量单元格,例如前 2 个单元格,然后是 3 个单元格,然后是 4 个单元格。然后只需滚动第一个单元格,看看打印出来的内容。为每个单元格执行此操作。 indexPath.item 和 postId 应该都匹配 cellForItemdidEndDisplaying

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-12-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多