我正在开发一个聊天应用程序,我有一个UICollectionView来控制消息,我想与你确认一个情况。
例如,假设我在此UICollectionView中有60个项目,但根据项目的大小和我设置的滚动选项,屏幕上只显示最后10个项目,从50到59
基于此,我似乎无法在IndexPath 30上获取cellForItem。这是对的吗?
我想在创建解决方案之前与您确认,以便查看已经在屏幕上显示的项目"我需要检查一下。您已经实施的任何想法和解决方案都表示赞赏。
另外,根据上述信息,例如,如果我需要将项目从索引路径30移动到31,如果它们没有被实例化,那么我是否会遇到问题"在屏幕上?
提前致谢!
答案 0 :(得分:2)
根据您的问题。如果屏幕上当前可见的单元格为50到59,则IndexPath 30上的cellForItem将不可用。这将是零。原因是该单元格已经被重复使用以显示50到59之间的一个单元格。
将单元格从30移动到31不会有问题。只需更新阵列/数据源并重新加载集合视图即可。
答案 1 :(得分:2)
您似乎正在混合您的模型,控制器和视图类,这是一件坏事,因为您遇到的原因正是如此。
我认为你试图从索引30(基本上)访问数据并对自己说'#34;嘿,我已经在第30个单元格中添加了这个,所以我将只使用集合视图&# 39;获取那个细胞并从那里取出的方法"。这意味着,您基本上会向视图询问数据。
这不会起作用,因为正如其他人指出的那样(但更间接地),在任何特定时刻都没有60个单元。屏幕上基本上有多少个单元格(加上可能是一个或几个"缓冲区"单元格,因此在滚动工作期间渲染,我无法记住atm)。这就是cellForItem(at:)
为IndexPath
为零的原因,UICollectionViewDataSource
指的是此刻实际上不可见的单元格。基本上它的工作方式与表视图类似。集合视图根本无法保留因内存原因而无需渲染的内容。
如果你需要在这条路径上从一个单元格(这毕竟也是一个视图)中任何,为什么不从任何数据对象中获取它代表这个单元格的内容?通常那就是UICollectionViewDataSource
。
该范例应该如何运作:UICollectionView
负责保留您的应用在给定时间可能需要的任何数据(这可能会也可能不会重新加载它或部分数据,你的选择)。当某个collectionView(_:cellForItemAt:)
变为可见时,IndexPath
会使用其collectionView(_:cellForItemAt:)
方法,但会再将其抛出(或者将其再次排队,以便您的数据源可以在UICollectionViewDataSource
中将其排队并将其重新用于另一个变得可见的数据集。
顺便说一下,请不要使用collectionView(_:cellForItemAt:)
的{{1}}方法来获取单元格,然后从那里获取数据。该方法应该由集合视图调用,并且取决于您如何重用单元格或创建它们,这可能会弄乱整个过程。或者至少创建与视图相关的开销。相反,获取数据的方式与UICollectionViewDataSource
进入方法内的方式相同。在您依赖的其他方法中包裹它或类似物。或者,更好的是,依赖控制器使用的模型对象。
根据您的评论进行修改:
不,我确实 意味着将UIViewController
用作UICollectionViewDataSource
作为UICollectionView
是不好的。我的意思是使用 UICollectionView
来获取数据,是不好的,因为那是什么数据源是。在你的问题中,你想知道为什么cellForItem(at:)
给出为零。该方法在UICollectionView
上定义。你没有提到你的意图是移动物品(我会在一秒钟内解释),所以我假设你试图得到细胞中的任何数据(我知道,"假设制造)你和我的屁股......",抱歉:))。这不是一种方法,因为UICollectionView
不是意味着为您保存数据。相反,这是你的工作,你可以使用UICollectionViewDataSource
。后一类(或者类可以采用的协议)基本上是为UICollectionView
提供接口来获取数据。它需要这样,因为如上所述,它并没有保留所有数据。它从数据源请求它需要的东西。另一方面,数据源本身可以管理该数据,或者它可能依赖于某种更深层次的体系结构(即处理底层模型的其他对象)来实现这一点。那部分取决于你的设计。对于具有数据源的较小场景,仅具有数组或字典中的数据就足够了。此外,许多设计实际上使用UIViewController to adopt
UICollectionViewDataSource`。这可能就足够了,但要注意不要将视图控制器炸成可以完成所有操作的怪物。这只是一个一般提示,你必须自己决定什么是"太多"。
现在,根据您的实际意图:移动细胞,您不需要获取它们。您只需告诉UICollectionView
将给定索引路径上的任何内容移动到其他索引路径。相应的方法是moveItem(at:to:)
。即使cellForItem(at:)
为两个索引路径之一返回nil,这也有效。集合视图将确保单元格在可见之前就在那里。它确实依赖于数据源,更具体地说是它的collectionView(_:cellForItemAt:)
方法。显然,这意味着您必须为移动准备好数据源,即它需要返回给定索引的正确单元格。那么在移动集合视图中的项目之前,改变数据源的内部存储(我假设一个数组?)。
有关详细信息,请参阅the documentation。另请注意,这基本上是如何以编程方式移动项目。如果你希望用户以交互方式移动它们(在一个对我来说似乎很奇怪的聊天中),它会变得有点复杂,但文档也有助于此。
答案 2 :(得分:0)
只有当您需要使用indexpath
以编程方式滚动非可见单元格时才能访问该单元格: -
collectionView.scrollToItem(at: yourIndexPath, at: UICollectionViewScrollPosition.top, animated: true)