使用UICollectionViewFlowLayout/UICollectionViewLayout子类,不会在正确的时间调用CellForItemAtIndexPath

iOS*_*com 7 cocoa-touch objective-c ios uicollectionview swift

这个问题不重复,虽然我在stavkOverflow上看到很多类似的问题.以下是我的代码的情况:

  1. 如果我的集合视图 UIStackView 之外,则正确调用CellForItemAtIndexPath.问题只发生在stackView内部

  2. 我已经从UICollectionViewFlowLayout正确地子类化了我的flowLayout.

  3. CollectionView正确返回numberOfSections和每个部分中的NumberOfItems.每个部分的项目数为42(6行×7列)

以下是问题所在:您可以看到它将到达未调用CellForItemAtIndexPath方法的位置.那里没有牢房.然后突然,当你到达滚动的某一点时,它会立即被调用,导致细胞出现.

在此输入图像描述

有谁知道错误是什么?如果UICollectionView未放置在UIStackView中,则不会发生此错误.

[编辑]

好.我已经缩小到UICollectionViewFlowLayout子类的问题.在那里有一小段代码可以将collectionView的布局更改为水平.意思是,视图上的单元格通常呈现如下:

[1][4][7]
[2][5][8]
[3][6][9]

//But the code should render it like this
[1][2][3]
[4][5][6]
[7][8][9]
Run Code Online (Sandbox Code Playgroud)

我有以下代码来执行此操作(取自KDCalendar).这段代码工作正常,但一旦它在stackView内部,它就会看到上面显示的内容.在stackView中,改变单元格顺序的方法是不同的?以下是导致问题的代码(仅在stackView内部)

override  public func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
    if let attrs = super.layoutAttributesForItemAtIndexPath(indexPath) {
        let attrscp = attrs.copy() as! UICollectionViewLayoutAttributes
        self.applyLayoutAttributes(attrscp)
        return attrscp
    }
    return nil
}

override public func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return super.layoutAttributesForElementsInRect(rect)?.map {
        attrs in
        let attrscp = attrs.copy() as! UICollectionViewLayoutAttributes
        self.applyLayoutAttributes(attrscp)
        return attrscp
    }
}

func applyLayoutAttributes(attributes : UICollectionViewLayoutAttributes) {
    if attributes.representedElementKind != nil {return}
    if let collectionView = self.collectionView {
        let stride = (self.scrollDirection == .Horizontal) ? collectionView.frame.size.width : collectionView.frame.size.height
        let offset = CGFloat(attributes.indexPath.section) * stride
        var xCellOffset : CGFloat = CGFloat(attributes.indexPath.item % 7) * self.itemSize.width
        var yCellOffset : CGFloat = CGFloat(attributes.indexPath.item / 7) * self.itemSize.height
        if(self.scrollDirection == .Horizontal) {
            xCellOffset += offset;
        } else {
            yCellOffset += offset
        }
        attributes.frame = CGRectMake(xCellOffset, yCellOffset, self.itemSize.width, self.itemSize.height)
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我想基本上我的问题是,通过继承UICollectionViewFlowLayout,如上所示,什么代码是水平渲染单元格的最快最有效的方法?我的collectionView将始终有7列.行只能是1,2,3或6.

[编辑]

我已将问题缩小到以下功能:

func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    //Inside this function, I have put the following code to test it.
    print(super.layoutAttributesForElementsInRect(rect))
}
Run Code Online (Sandbox Code Playgroud)

这是我得到的打印输出

  • [0]:索引路径:({length = 2,path = 0 - 0}); frame =(0 0; 59.1429 72.8333);
    • 1:索引路径:({length = 2,path = 0 - 1}); frame =(0 73; 59.1429 72.8333);
    • [2]:索引路径:({length = 2,path = 0 - 2}); frame =(0 145.667; 59.1429 72.8333);
    • [3]:索引路径:({length = 2,path = 0 - 3}); frame =(0 218.667; 59.1429 72.8333);
    • [4]:索引路径:({length = 2,path = 0 - 4}); frame =(0 291.333; 59.1429 72.8333);
    • [5]:索引路径:({length = 2,path = 0 - 5}); frame =(0 364.333; 59.1429 72.8333);
    • [6]:索引路径:({length = 2,path = 0 - 6}); frame =(59 0; 59.1429 72.8333);
    • [7]:索引路径:({length = 2,path = 0 - 7}); frame =(59 73; 59.1429 72.8333);
    • [8]:索引路径:({length = 2,path = 0 - 8}); frame =(59 145.667; 59.1429 72.8333);
    • [9]:索引路径:({length = 2,path = 0 - 9}); frame =(59 218.667; 59.1429 72.8333);
    • [10]:索引路径:({length = 2,path = 0 - 10}); frame =(59 291.333; 59.1429 72.8333);
    • [11]:索引路径:({length = 2,path = 0 - 11}); frame =(59 364.333; 59.1429 72.8333);
    • [12]:索引路径:({length = 2,path = 0 - 12}); frame =(118.333 0; 59.1429 72.8333);
    • [13]:索引路径:({length = 2,path = 0 - 13}); frame =(118.333 73; 59.1429 72.8333);
    • [14]:索引路径:({length = 2,path = 0 - 14}); frame =(118.333 145.667; 59.1429 72.8333);
    • [15]:索引路径:({length = 2,path = 0 - 15}); frame =(118.333 218.667; 59.1429 72.8333);
    • [16]:索引路径:({length = 2,path = 0 - 16}); frame =(118.333 291.333; 59.1429 72.8333);
    • [17]:索引路径:({length = 2,path = 0 - 17}); frame =(118.333 364.333; 59.1429 72.8333);
    • [18]:索引路径:({length = 2,path = 0 - 18}); frame =(177.333 0; 59.1429 72.8333);
    • [19]:索引路径:({length = 2,path = 0 - 19}); frame =(177.333 73; 59.1429 72.8333);
    • [20]:索引路径:({length = 2,path = 0 - 20}); frame =(177.333 145.667; 59.1429 72.8333);
    • [21]:索引路径:({length = 2,path = 0 - 21}); frame =(177.333 218.667; 59.1429 72.8333);
    • [22]:索引路径:({length = 2,path = 0 - 22}); frame =(177.333 291.333; 59.1429 72.8333);
    • [23]:索引路径:({length = 2,path = 0 - 23}); frame =(177.333 364.333; 59.1429 72.8333);
    • [24]:索引路径:({length = 2,path = 0 - 24}); frame =(236.667 0; 59.1429 72.8333);
    • [25]:索引路径:({length = 2,path = 0 - 25}); frame =(236.667 73; 59.1429 72.8333);
    • [26]:索引路径:({length = 2,path = 0 - 26}); frame =(236.667 145.667; 59.1429 72.8333);
    • [27]:索引路径:({length = 2,path = 0 - 27}); frame =(236.667 218.667; 59.1429 72.8333);
    • [28]:索引路径:({length = 2,path = 0 - 28}); frame =(236.667 291.333; 59.1429 72.8333);
    • [29]:索引路径:({length = 2,path = 0 - 29}); frame =(236.667 364.333; 59.1429 72.8333);
    • [30]:索引路径:({length = 2,path = 0 - 30}); frame =(295.667 0; 59.1429 72.8333);
    • [31]:索引路径:({length = 2,path = 0 - 31}); frame =(295.667 73; 59.1429 72.8333);
    • [32]:索引路径:({length = 2,path = 0 - 32}); frame =(295.667 145.667; 59.1429 72.8333);
    • [33]:索引路径:({length = 2,path = 0 - 33}); frame =(295.667 218.667; 59.1429 72.8333);
    • [34]:索引路径:({length = 2,path = 0 - 34}); frame =(295.667 291.333; 59.1429 72.8333);
    • [35]:索引路径:({length = 2,path = 0 - 35}); frame =(295.667 364.333; 59.1429 72.8333);
    • [36]:索引路径:({length = 2,path = 0 - 36}); frame =(355 0; 59.1429 72.8333);
    • [37]:索引路径:({length = 2,path = 0 - 37}); frame =(355 73; 59.1429 72.8333);
    • [38]:索引路径:({length = 2,path = 0 - 38}); frame =(355 145.667; 59.1429 72.8333);
    • [39]:索引路径:({length = 2,path = 0 - 39}); frame =(355 218.667; 59.1429 72.8333);
    • [40]:索引路径:({length = 2,path = 0 - 40}); frame =(355 291.333; 59.1429 72.8333);
    • [41]:索引路径:({length = 2,path = 0 - 41}); frame =(355 364.333; 59.1429 72.8333);
    • [42]:索引路径:({length = 2,path = 1 - 0}); frame =(414 0; 59.1429 72.8333);
    • [43]:索引路径:({length = 2,path = 1 - 1}); frame =(414 73; 59.1429 72.8333);
    • [44]:索引路径:({length = 2,path = 1 - 2}); frame =(414 145.667; 59.1429 72.8333);
    • [45]:索引路径:({length = 2,path = 1 - 3}); frame =(414 218.667; 59.1429 72.8333);
    • [46]:索引路径:({length = 2,path = 1 - 4}); frame =(414 291.333; 59.1429 72.8333);
    • [47]:索引路径:({length = 2,path = 1 - 5}); frame =(414 364.333; 59.1429 72.8333);
    • [48]:索引路径:({length = 2,path = 1 - 6}); frame =(473 0; 59.1429 72.8333);
    • [49]:索引路径:({length = 2,path = 1 - 7}); frame =(473 73; 59.1429 72.8333);
    • [50]:索引路径:({length = 2,path = 1 - 8}); frame =(473 145.667; 59.1429 72.8333);
    • [51]:索引路径:({length = 2,path = 1 - 9}); frame =(473 218.667; 59.1429 72.8333);
    • [52]:索引路径:({length = 2,path = 1 - 10}); frame =(473 291.333; 59.1429 72.8333);
    • [53]:索引路径:({length = 2,path = 1 - 11}); frame =(473 364.333; 59.1429 72.8333);
    • [54]:索引路径:({length = 2,path = 1 - 12}); frame =(532.333 0; 59.1429 72.8333);
    • [55]:索引路径:({length = 2,path = 1 - 13}); frame =(532.333 73; 59.1429 72.8333);
    • [56]:索引路径:({length = 2,path = 1 - 14}); frame =(532.333 145.667; 59.1429 72.8333);
    • [57]:索引路径:({length = 2,path = 1 - 15}); frame =(532.333 218.667; 59.1429 72.8333);
    • [58]:索引路径:({length = 2,path = 1 - 16}); frame =(532.333 291.333; 59.1429 72.8333);
    • [59]:索引路径:({length = 2,path = 1 - 17}); frame =(532.333 364.333; 59.1429 72.8333);
    • [60]:索引路径:({length = 2,path = 1 - 18}); frame =(591.333 0; 59.1429 72.8333);
    • [61]:索引路径:({length = 2,path = 1 - 19}); frame =(591.333 73; 59.1429 72.8333);
    • [62]:索引路径:({length = 2,path = 1 - 20}); frame =(591.333 145.667; 59.1429 72.8333);
    • [63]:索引路径:({length = 2,path = 1 - 21}); frame =(591.333 218.667; 59.1429 72.8333);
    • [64]:索引路径:({length = 2,path = 1 - 22}); frame =(591.333 291.333; 59.1429 72.8333);
    • [65]:索引路径:({length = 2,path = 1 - 23}); frame =(591.333 364.333; 59.1429 72.8333);
    • [66]:索引路径:({length = 2,path = 1 - 24}); frame =(650.667 0; 59.1429 72.8333);
    • [67]:索引路径:({length = 2,path = 1 - 25}); frame =(650.667 73; 59.1429 72.8333);
    • [68]:索引路径:({length = 2,path = 1 - 26}); frame =(650.667 145.667; 59.1429 72.8333);
    • [69]:索引路径:({length = 2,path = 1 - 27}); frame =(650.667 218.667; 59.1429 72.8333);
    • [70]:索引路径:({length = 2,path = 1 - 28}); frame =(650.667 291.333; 59.1429 72.8333);
    • [71]:索引路径:({length = 2,path = 1 - 29}); frame =(650.667 364.333; 59.1429 72.8333);
    • [72]:索引路径:({length = 2,path = 1 - 30}); frame =(709.667 0; 59.1429 72.8333);
    • [73]:索引路径:({length = 2,path = 1 - 31}); frame =(709.667 73; 59.1429 72.8333);
    • [74]:索引路径:({length = 2,path = 1 - 32}); frame =(709.667 145.667; 59.1429 72.8333);
    • [75]:索引路径:({length = 2,path = 1 - 33}); frame =(709.667 218.667; 59.1429 72.8333);
    • [76]:索引路径:({length = 2,path = 1 - 34}); frame =(709.667 291.333; 59.1429 72.8333);
    • [77]:索引路径:({length = 2,path = 1 - 35}); frame =(709.667 364.333; 59.1429 72.8333);

我可以看到,功能要求的索引路径:0-00-41为第0,这是正确的.但是,它只要求索引路径1-01-35用于其他部分.它缺少其他6个indexPath.当用户将丢失的单元格很好地滚动到视图中时,它仅呈现其他6个路径.有没有理由不返回所有索引?这甚至是检测矩形细胞的正确方法吗?

jtb*_*des 6

你的基本缺陷是存在的JTAppleCalendarFlowLayout.

UICollectionView内部依赖于layoutAttributesForElementsInRect()知道要请求的单元layoutAttributesForItemAtIndexPath.由于您super没有修改就传递了rect ,因此无法正确理解哪些单元格应该可见.

为了更好地演示这个问题,我制作了一个保持同步的集合视图的第二个副本,但是在底部的一个上禁用了你的applyLayoutAttributes修改.我也把那些看起来太晚的细胞着色了.

演示动画

您必须了解的部分是在顶部collectionView中显示"太晚"的单元格在原始/未修改的布局中尚不可见.集合视图仅在认为它们很快就会被添加时添加它们.它没有意识到你实际上已经让它们可见了.

那么......你应该怎么解决它?

由于您的布局非常简单,我建议您不要打扰UICollectionViewFlowLayout,因为它不是设计用于以这种方式处理"页面".只需子类化UICollectionViewLayout,并使用自定义计算自己实现layoutAttributesForElementsInRect和layoutAttributesForItemAtIndexPath.

或者,如果您真的使用UICollectionViewFlowLayout,则需要修改传递给的矩形,super以便在原始布局下,rect将包含在修改后的布局下可见的所有单元格.