美文网首页iOS学习笔记
UICollectionView的cellForItem(at:

UICollectionView的cellForItem(at:

作者: 木头人小7 | 来源:发表于2017-03-02 16:50 被阅读0次

首先,需求是做一个选择颜色的小组件。如下图所示


效果图

需要滑动展示,8种颜色,一页显示4个,共两页。
我选择了UICollectionView来做。因为颜色图片是直接用Graphics画的,就直接把绘制出来的CGImage赋值给了UICollectionViewCell的contentView.layer.contents属性。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: UICollectionViewCell.reuseIdentifier, for: indexPath)
    let colorType = viewModel!.colors[indexPath.section][indexPath.item]
    if colorType == viewModel!.selectedColor {
        cell.contentView.layer.contents = cgImage(for: .selected, colorType: colorType)
    }else {
        cell.contentView.layer.contents = cgImage(for: .normal, colorType: colorType)
    }
    return cell
}

主要的代理方法如下:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)
    cell?.contentView.layer.contents = cgImage(for: .selected,
                                               colorType: viewModel!.colors[indexPath.section][indexPath.item])
    viewModel!.selectedColor = viewModel!.colors[indexPath.section][indexPath.item]
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)
    cell?.contentView.layer.contents = cgImage(for: .normal,
                                               colorType: viewModel!.colors[indexPath.section][indexPath.item])
}

看上去很完美,我也是这么认为的。可当我愉快的选来选去的时候,出现了这种情况:

选中第二页的第一个,再选择上一页的任意一个,第二页那个被选中的状态不改变
我第一反应是,难道didDeselect方法没有执行?经过断点发现,这个方法是执行了,indexPath也是正确传递了上一次被选中cell的位置。但是在didDeselect方法中使用collectionView.cellForItem(at: indexPath)得到的结果是nil。

出现不知道的问题了怎么办?看文档。
cellForItem(at:)的官方说明是 "Returns the visible cell object at the specified index path."

好吧,我承认我的基础知识很烂。我是个智障。。。
因为集合视图会创建最大可见cell数 maxVisibled+1个cell,滑动中,超出这个范围的cell会被放进缓冲区,即将出现的第maxVisibled+2个cell才会调用cellForItemAt indexPath:方法获取,可能从缓冲池取,可能重新创建(缓冲池里没有可复用的cell时)。但是本例中 [1, 0] 和 [0, 3] 这两个位置的cell很尴尬,因为它们永远不会被放进缓冲区,不会被重新获取,状态就不会被重置。cellForItem(at: indexPath) 又无法取到不可见的cell,所以它们一旦被选中就无法取消了(除非在本页中再次选中它,再在本页中选中其他cell)。解决办法也很简单,增加一个变量持有被选中的cell来维护是否选中状态就行了。
不说了,我看文档去了。。。

好吧,我又回来了。。。
我发现压根不用这么麻烦。。直接重写UICollectionViewCell的 isSelected 属性的didSet方法,在这个方法里更换图片就行了。。。因为这里的UICollectionView的allowsMultipleSelection是false,并不允许多选,所以选择其他cell时,会自动取消上一个被选中cell的选中状态。。。

相关文章

网友评论

    本文标题:UICollectionView的cellForItem(at:

    本文链接:https://www.haomeiwen.com/subject/fztkgttx.html