在UITableView或UICollectionView上加载与可见单元格 [英] Getting loaded vs visible cells on a UITableView or UICollectionView

查看:81
本文介绍了在UITableView或UICollectionView上加载与可见单元格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

随着iOS 10的推出,似乎我们将默认在UITableView上启用预取和UICollectionViews .这意味着未在屏幕上显示的单元格将在用户实际看到它们之前获取.

以下是一些相关方法:

UITableView :

UICollectionView :

所有这些在其描述中都特别提到了可见".随着iOS 10中的预取功能的引入,我如何区分预取的单元格与当前可见的单元格?

换句话说:

  1. 我如何获得所有可见的细胞?
  2. 如何获取所有已加载的单元格?

在UITableView或UICollectionView上似乎没有任何新的API可以帮助解决此问题.

解决方案

TL; DR

  • 按原样在函数名称中使用 visible .
  • UITableView的行为与在iOS 9中一样.
  • 如果要在iOS 10的UICollectionView中以不同方式处理加载的单元格与可见单元格,则需要做一些记账.

在预取方面,UITableView和UICollectionView的行为似乎大不相同.

首先要注意的是,预取单元格和预取数据之间是有区别的:

  • 预取单元格是指在单元格实际显示在屏幕上之前调用的 cellForRowAtIndexPath .这样可以实现您的单元格处于屏幕外但仍处于加载状态的情况.
  • 预取数据是指 prefetchDataSource 方法,这些方法会通知您即将在屏幕上显示的 indexPaths .调用此方法时,您没有对单元格的引用,并且调用此方法时,您没有返回单元格.取而代之的是,此方法应该执行一些操作,例如触发网络请求以下载将显示在单元格中的图像.

注意:在所有这些情况下,假设在任何给定时间可以显示8个单元格.

UITableView :(选项:不预取,或预取数据)

  • 永远不会预取单元格.换句话说,它将永远不会在未显示的 indexPath 上调用 cellForRowAtIndexPath .
  • 如此,UITableView上没有 isPrefetchingEnabled 属性.
  • 您可以选择使用 prefetchDataSource 来预取数据.
  • 请注意,尽管表格视图确实看起来对单元格的重新使用不太积极,但它似乎仍然当重新使用的单元格重新显示在屏幕上时,请调用 cellForItemAtIndexPath .(尽管我可能需要对此进行更多调查,尤其是对于集合视图.)

UICollectionView :(选项:不预取预取单元格预取单元格和数据)

    默认情况下,
  • 预取单元格.换句话说,它将为不会立即显示的单元格调用 cellForItemAtIndexPath .
  • 仅当用户在集合视图上向上或向下滚动时才开始单元格的预取.换句话说,加载视图时,您将确切地获得8个对 cellForItemAtIndexPath 的调用.仅当用户向下滚动时,它才会开始询问不可见的单元格(例如,如果您向下滚动以显示2-10,则可能会要求输入11-14).
  • 当预取的,不可见的单元格出现在屏幕上时,它不会再次调用 cellForItemAtIndexPath .假设您第一次执行的实例仍然有效.
  • 您可以选择使用 prefetchDataSource 来预取数据.
  • prefetchDataSource 原来仅对初始加载有用.在上述相同情况下,例如,当显示前8个单元格时,它可能会触发对单元格9-14的数据的预取.但是,一旦调用了此初始方法,此后就没有用了.这是因为 cellForItemAtIndexPath 将在每次调用 prefetchItemsAt 之后立即被调用.例如,您将立即得到 prefetchItemsAt:[14,15] ,然后是 cellForItemAt:14 cellForItemAt:15 .
  • 您可以通过设置 isPrefetchingEnabled = false 来选择退出 all 所有预取行为.这意味着您不能使UICollectionView的行为类似于具有 prefetchDataSource 的UITableView的行为.或者,换句话说,您不能仅具有UICollectionView 预取数据.

两者都:

  • visibleCells indexPathsForVisibleRows cellForItemAtIndexPath 的用法与他们所说的完全一样:它们仅处理 visible 单元格.在相同的情况下,如果加载了20个单元,但屏幕上只有8个可见.所有这三种方法都只会报告8个屏幕单元格.

那是什么意思?

  • 如果您使用的是UITableView,则可以按原样使用它,而不必担心加载的单元格与可见的单元格之间的差异.它们总是等效的.
  • 另一方面,对于UICollectionView,如果您关心这种差异,则需要做一些记账以跟踪加载的,不可见的单元格与可见的单元格.您可以通过查看数据源上的某些方法和委托方法(例如willDisplayCell,didEndDisplayingCell)来做到这一点.

With the introduction of iOS 10, it seems like we're going to have prefetching enabled by default on UITableView and UICollectionViews. This means that cells that aren't displayed on the screen are going to be fetched before the user actually sees them.

Here are some relevant methods:

UITableView:

UICollectionView:

All these specifically mention "visible" in their descriptions. With the introduction of pre-fetching in iOS 10, how would I distinguish between a cell that was pre-fetched vs. one that is currently visible?

In other words:

  1. How do I get all visible cells?
  2. How do I get all loaded cells?

It does not look like there are any new APIs on either UITableView or UICollectionView that can help with this.

解决方案

TL;DR

  • Take the visible in function names literally.
  • UITableView behaves just as it did in iOS 9.
  • You'll need to do some bookkeeping if you want to treat loaded vs. visible cells differently in UICollectionView on iOS 10.

UITableView and UICollectionView appear to behave very differently when it comes to prefetching.

First thing to notice is that there is a difference between prefetching cells and prefetching data:

  • Prefetching cells refers to the cellForRowAtIndexPath being called before the cell is actually displayed on screen. This enables the scenario where you have cells that are off-screen but still loaded.
  • Prefetching data refers to the prefetchDataSource methods which inform you about indexPaths that are going to be displayed on screen. You do not have a reference to the cell when this method is called, and you do not return a cell when this method is called. Instead, this method should do things like fire off a network request to download an image that will be displayed in the cell.

Note: In all of these scenarios, imagine there are 8 cells that can be displayed at any given time.

UITableView: (options: no prefetching, or prefetch data)

  • Does not prefetch cells, ever. In other words, it will never call cellForRowAtIndexPath on an indexPath that isn't displayed.
  • As such, there is no isPrefetchingEnabled property on a UITableView.
  • You can opt-in to prefetching data by using the prefetchDataSource.
  • Note that although the table view does seem to be less aggressive with reusing cells, it still appears to call cellForItemAtIndexPath when the reused cell comes back on screen. (Although I may need to do some more investigation as to this, especially for collection views.)

UICollectionView: (options: no prefetching, prefetch cells, or prefetch cells and data)

  • Prefetches cells by default. In other words, it will call cellForItemAtIndexPath for cells that aren't going to be immediately displayed.
  • The prefetching of cells only begins when the user scrolls up or down on the collection view. In other words, you will get exactly 8 calls to cellForItemAtIndexPath when the view is loaded. Only once the user scrolls down will it start asking for non-visible cells (e.g. if you scrolled down to show 2-10, it might ask for 11-14).
  • When the prefetched, non-visible cell comes on screen, it's not going to call cellForItemAtIndexPath again. It's going to assume that instantiation you did the first time is still valid.
  • You can opt-in to prefetching data by using the prefetchDataSource.
  • The prefetchDataSource turns out to be only useful for the initial load. In the same scenario above, when the first 8 cells are displayed, it may fire off a prefetching of data for cells 9-14, for example. However, once this initial method is called, it's useless thereafter. This is because cellForItemAtIndexPath is going to be called immediately after each call to prefetchItemsAt. For example, you'll get prefetchItemsAt:[14, 15] immediately followed by cellForItemAt:14, cellForItemAt:15.
  • You can opt-out of all prefetching behavior by setting isPrefetchingEnabled = false. This means you can't make a UICollectionView behave similarly to a UITableView with a prefetchDataSource. Or, in other words, you can not have a UICollectionView prefetch data only.

For both:

  • visibleCells, indexPathsForVisibleRows, and cellForItemAtIndexPath do exactly as they say: they only deal with visible cells. In our same scenario, if we have 20 cells loaded, but only 8 are visible on screen. All 3 of these methods will only report about the 8 on-screen cells.

So what does this mean?

  • If you're using a UITableView, you can use it as is and never have to worry about a difference between loaded vs. visible cells. They are always equivalent.
  • For UICollectionView, on the other hand, you're gonna need to do some book-keeping to keep track of loaded, non-visible cells vs. visible cells if you care about this difference. You can do this by looking at some of the methods on the data source and delegate methods (e.g. willDisplayCell, didEndDisplayingCell).

这篇关于在UITableView或UICollectionView上加载与可见单元格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆