为啥将 UICollectionViewLayout 分配给 UICollectionView 后 UICollectionViewCells 不再可见?

Posted

技术标签:

【中文标题】为啥将 UICollectionViewLayout 分配给 UICollectionView 后 UICollectionViewCells 不再可见?【英文标题】:Why are UICollectionViewCells no longer visibile after assigning a UICollectionViewLayout to the UICollectionView?为什么将 UICollectionViewLayout 分配给 UICollectionView 后 UICollectionViewCells 不再可见? 【发布时间】:2015-05-06 13:42:08 【问题描述】:

我的应用有一个UIViewController 类;在这个类中,我连接了一个从 Storyboard 加载的UICollectionView

我正在使用 UICollectionViewLayout 类创建自定义布局。这是它的样子:

class MyLayout: UICollectionViewLayout 

    override func prepareLayout() 
        super.prepareLayout()
    

    override func collectionViewContentSize() -> CGSize 
        let attributes = super.collectionViewContentSize()
        return attributes
    

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? 
        let attributes = super.layoutAttributesForElementsInRect(rect) as? [UICollectionViewLayoutAttributes]
        return attributes
    

    override func layoutAttributesForItemAtIndexPath(indexPath:
    NSIndexPath) -> UICollectionViewLayoutAttributes 
        let attributes = super.layoutAttributesForItemAtIndexPath(indexPath)
        return attributes
    

要将UICollectionViewLayout 分配给UICollectionView,我使用UICollectionViewcollectionViewLayout 属性:

myCollectionView.collectionViewLayout = MyLayout()

运行应用程序,UICollectionViewCells 不再可见。不过,在分配 UICollectionViewLayout 之前,它们是可见的。我现在只能看到UICollectionView的背景。

为什么细胞不再可见?

更新

我仔细查看了UICollectionViewUICollectionViewLayoutAttributes,尤其是contentSize。我打印了它的值,它似乎等于(0.0, 0.0)layoutAttributesForElementsInRectattributes 值也等于 nil。绝对是一个危险信号。

Download the project

【问题讨论】:

您在使用自动布局吗?如果是,那么你需要设置约束 是的,我正在使用 AutoLayout。我应该对什么附加约束? UICollectionView? UICollectionViewCells?谢谢! 你需要给 UICollectionView 提供约束,看看这个:***.com/questions/25804588/… 检查这个例子:randexdev.com/2014/07/uicollectionview 感谢您的链接。似乎没有办法为UICollectionViewUICollectionViewCell 创建新的约束。我在UICollectionViewCell 类中实现了this 代码,但没有任何效果。 【参考方案1】:

我认为您可以保持几乎所有内容完全相同。将自定义布局的类类型更改为UICollectionViewFlowLayout

class myLayout: UICollectionViewFlowLayout 
    //all your code here

另外,将 myLayout 更改为 MyLayout 以更好地衡量:)

【讨论】:

感谢您的回答@Frankie!我更改了课程的类型,但 UICollectionCells 仍然没有出现。我发现UICollectionViewcontentSize 等于(0.0, 0.0),这绝对是一个危险信号。似乎没有显示单元格,因为UICollectionView 太小了。我正在寻找一种方法来使用正确的contentSize,即使我确保 AutoLayout 约束创建得很好。非常感谢您的帮助! 是的,0,0 不对。我清除了所有约束并且它运行良好,所以它仍然可能是你的约束的问题:/ 你的 collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize 方法中有什么? 感谢您帮助我解决这个问题!在该方法中,我只返回此代码:return CGSize(width: 130, height: 130)。我确定了故事板文件中的宽度和高度的数学值。也许我还缺少其他一些方法?目前在我的UICollectionViewController 中,我有cellForItemAtIndexPathsizeForItemAtIndexPathnumberOfItemsInSection 方法。我还需要其他方法吗?谢谢! 如果您删除自定义布局,您的收藏视图是否仍然有效?如果是这样,那么你不会错过任何东西。告诉我。 是的,确实如此。我想我的应用程序视图的放置发生了一些事情。在viewDidLoad 方法中,我使用以下代码将单元格置于顶部:self.view.bringSubviewToFront(cells)。不过,没有什么新的事情发生。【参考方案2】:

首先,你应该用你的布局初始化你的 UICollectionView,而不是事后设置它:

var collectionView = UICollectionView(frame: frame, collectionViewLayout: myLayout)

来自documentation:

您通常在创建集合视图时指定一个布局对象 [...]

接下来,如果您继承 UICollectionViewLayout,您必须实现 collectionViewContentSize 并返回您自己的值。在这里调用 super 是未定义的,除非您是子类化 UICollectionViewFlowLayout

子类必须重写此方法并使用它来返回集合视图内容的宽度和高度。这些值表示所有内容的宽度和高度,而不仅仅是当前可见的内容。集合视图使用此信息来配置其自己的内容大小以用于滚动。

这是因为 UICollectionViewLayout 本身就是一个抽象类,它什么都不做(它应该被子类化)。

UICollectionViewLayout 类是一个抽象基类,您可以将其子类化并用于生成集合视图的布局信息。

同样,您还需要在layoutAttributesForElementsInRect: 中计算自己的layoutAttributes。最简单的方法是在prepareLayout 方法中计算所有需要的布局,然后再获取所需的布局。这是自定义布局的“核心”:

向代表询问您必须在 collectionView 中显示的元素数量。 对于每个元素,首先创建正确的 indexPath,然后使用 UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath) 为该 indexPath 创建一个空的 layoutAttribute。 计算并设置该 layoutAttribute 的 frame 属性。 将该 layoutAttribute 存储在声明为 MutableArray 的私有属性中。 在layoutAttributesForElementsInRect: 中,遍历您之前实例化的所有存储布局属性,并返回其中frame 与提供的rect 相交的子集。 UICollectionView 将要求其 dataSource 为该方法返回的每个 layoutAttributes 提供一个单元格(通过 cellForItemAtIndexPath),这些单元格的 frame 将使用这些单元格中的 frame 属性设置布局属性。

如果你能读懂 Objective-C 和 Swift,你可以看看 my sample UICollectionViewLayout implementation here,它使 UICollectionView 模仿了 ios 日历应用程序的每日视图 (screenshot)。

如果您的目标是实现一个相当标准的布局(即布置在水平或垂直流动的网格中的元素),我建议您从子类化 UICollectionViewFlowLayout 开始,因为它已经是一个有效的实现UICollectionViewLayout,这意味着您可以在大多数方法中使用 super 来获取默认值。

另外,请阅读 here in the official documentation 了解如何创建自己的自定义布局。

【讨论】:

非常感谢您的回答!我很快就会检查出来。你在那里提出了一些好观点! @CeceXX 不客气!如果还有什么不清楚的地方告诉我,使用自定义布局有时会很麻烦。 谢谢!我想我必须使用UICollectionViewLayout 来启用水平和垂直滚动。处理layoutAttributesForElementsInRect: 是我唯一关心的问题。你会在layoutAttributesForElementsInRect: 方法中插入什么来使我的应用程序按预期工作?我仍然不明白该方法返回什么。再次感谢您的帮助! @CeceXX 我在回答中添加了有关layoutAttributesForElementsInRect: 的更多详细信息。我建议您在 prepareLayout 方法中计算所有布局并将它们存储在一个数组中,然后在 layoutAttributesForElementsInRect: 中遍历它们以仅返回那些计算框架与作为参数提供的框架相交的那些。如何计算这些框架取决于您,这取决于您希望单元格如何显示,但它们通常基于项目索引和部分。 我找不到更好的解释了!我现在走在正确的轨道上。赏金将在 1 小时内到来 :-)

以上是关于为啥将 UICollectionViewLayout 分配给 UICollectionView 后 UICollectionViewCells 不再可见?的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView(3x3 Grid)与静态单元格分页

尽管宽度相等,但集合视图网格最后一行的显示方式不同 - swift iOS

为啥 math.inf 是浮点数,为啥我不能将其转换为整数?

为啥在链表中查找循环时将指针增加 2,为啥不增加 3、4、5?

为啥注册用户未在 Firebase 中进行身份验证?为啥用户不能将产品添加到数据库 Firebase?

为啥我们将字符串数组作为参数传递给 main() 方法,为啥不传递任何集合类型或包装类型或原始类型?