iOS swift UICollectionView在滚动过第一个满屏幕后将丢失单元格约束

iOS swift UICollectionView在滚动过第一个满屏幕后将丢失单元格约束,ios,swift,uicollectionview,Ios,Swift,Uicollectionview,我正在尝试学习如何在Swift iOS应用程序中处理UICollectionViews,这只是一个简单的应用程序,它在单元格中显示图像和标签25次。最初,错误的约束阻止CollectionView显示任何内容,但一旦我解决了这些问题,CollectionView就会按照预期显示单元格。根据我的布局方法显示了所有25项的调试消息 然后我向下滚动,一旦它通过了第11项,它似乎完全失去了布局,如下图所示。向上滚动,它更不稳定,所有的单元格都变成了一个完整大小的图像 代码没有什么特别之处,尤其是布局-

我正在尝试学习如何在Swift iOS应用程序中处理UICollectionViews,这只是一个简单的应用程序,它在单元格中显示图像和标签25次。最初,错误的约束阻止CollectionView显示任何内容,但一旦我解决了这些问题,CollectionView就会按照预期显示单元格。根据我的布局方法显示了所有25项的调试消息

然后我向下滚动,一旦它通过了第11项,它似乎完全失去了布局,如下图所示。向上滚动,它更不稳定,所有的单元格都变成了一个完整大小的图像

代码没有什么特别之处,尤其是布局-以下是代码:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        if indexPath.item > 10 {
        // Limit number of debug messages
            print("view.bounds: \(view.bounds)")
            print("collectionView.bounds: \(collectionView.bounds)")
            print("collectionView.alignmentRectInsets: \(collectionView.alignmentRectInsets)")
            print("collectionView.contentInset: \(collectionView.contentInset)")
        }
        let width = view.bounds.width
        print("width[\(indexPath.item)]: \(width)")
        let cellDimension = (width / 2 ) - 15
        print("cellDimension[\(indexPath.item)]: \(cellDimension)")
        let returnSize = CGSize(width: cellDimension, height: cellDimension)
        print("returnSize[\(indexPath.item)]: \(returnSize)")
        return returnSize
    }
一旦超过第11项,调试器就会开始发出大量的消息:

2019-10-22 01:32:54.794032-0500 CollectionTest#1[13173:339022] The behavior of the UICollectionViewFlowLayout is not defined because:
2019-10-22 01:32:54.794203-0500 CollectionTest#1[13173:339022] the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
2019-10-22 01:32:54.794360-0500 CollectionTest#1[13173:339022] Please check the values returned by the delegate.
2019-10-22 01:32:54.794856-0500 CollectionTest#1[13173:339022] The relevant UICollectionViewFlowLayout instance is <UICollectionViewFlowLayout: 0x7fe4c1407750>, and it is attached to <UICollectionView: 0x7fe492819400; frame = (0 0; 414 736); clipsToBounds = YES; autoresize = LM+W+RM+TM+H+BM; gestureRecognizers = <NSArray: 0x600000965050>; layer = <CALayer: 0x60000076efe0>; contentOffset: {0, 355}; contentSize: {414, 2512}; adjustedContentInset: {20, 0, 0, 0}> collection view layout: <UICollectionViewFlowLayout: 0x7fe4c1407750>.
2019-10-22 01:32:54.801289-0500 CollectionTest#1[13173:339022] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
This just goes on and on ... abbreviated for brevity.
顺便说一下,使用哪个版本的运行时模拟器似乎没有任何区别


在我还有头发要拔的时候,非常感谢您的帮助、指点、建议等。谢谢。

尝试将
cellImage
内部
CollectionViewCell
clipToBounds
属性设置为
true
,即

class CollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var cellImage: UIImageView!

    override func awakeFromNib() {
        super.awakeFromNib()
        self.cellImage.clipsToBounds = true //here..
    }
    //rest of the code....
}
您还可以在UI本身中设置
cellImage
clipToBounds
,即


注意:
CollectionViewCell
中移动单元格布局的所有代码,而不是在
cellForItemAt
中写入所有内容。这将减少代码的体积和可读性。

尝试将
cellImage
内部
CollectionViewCell
clipToBounds
属性设置为
true
,即

class CollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var cellImage: UIImageView!

    override func awakeFromNib() {
        super.awakeFromNib()
        self.cellImage.clipsToBounds = true //here..
    }
    //rest of the code....
}
您还可以在UI本身中设置
cellImage
clipToBounds
,即


注意:
CollectionViewCell
中移动单元格布局的所有代码,而不是在
cellForItemAt
中写入所有内容。这将减少代码的体积和可读性。

谢谢您的建议。我发现了一篇关于堆栈溢出的文章,它将我推向了一个似乎有助于解决问题的方向

我可能是错的,但我的观察结果告诉我,似乎并非所有的单元格都是根据情节提要值初始化大小的。前十几个单元都是这样做的,但当集合视图开始重用/回收单元时,它就无法跟踪单元大小。我尝试在cellForItemAt()中设置单元格大小,但这会导致一些非常糟糕的递归问题

通过调试器观察,sizeForItemAt()只在最初被调用,而不是在单元格开始被重用时,当单元格大小丢失时,各种不希望发生的事情开始发生

在viewDidLoad()中初始化单元格大小消除了大部分问题,也就是说,在设备旋转之前,sizeForItemAt()会在iPhone模拟器中为新布局调用,但不会在iPad模拟器中调用

解决方法是在viewDidLoad()中检查设备类型,并计算每行所需的单元数。如果在设备旋转时希望每行有不同数量的单元格,那么简单地设置布局的单元格大小并不能完全解决问题

至少就目前而言,这似乎已经缓和了问题


我只是有点担心我遗漏了一些东西,因为SizeForestMat()函数没有按预期调用。

谢谢你的建议。我发现了一篇关于堆栈溢出的文章,它将我推向了一个似乎有助于解决问题的方向

我可能是错的,但我的观察结果告诉我,似乎并非所有的单元格都是根据情节提要值初始化大小的。前十几个单元都是这样做的,但当集合视图开始重用/回收单元时,它就无法跟踪单元大小。我尝试在cellForItemAt()中设置单元格大小,但这会导致一些非常糟糕的递归问题

通过调试器观察,sizeForItemAt()只在最初被调用,而不是在单元格开始被重用时,当单元格大小丢失时,各种不希望发生的事情开始发生

在viewDidLoad()中初始化单元格大小消除了大部分问题,也就是说,在设备旋转之前,sizeForItemAt()会在iPhone模拟器中为新布局调用,但不会在iPad模拟器中调用

解决方法是在viewDidLoad()中检查设备类型,并计算每行所需的单元数。如果在设备旋转时希望每行有不同数量的单元格,那么简单地设置布局的单元格大小并不能完全解决问题

至少就目前而言,这似乎已经缓和了问题


我只是有点担心我遗漏了一些东西,因为sizeForItemAt()函数没有按预期调用。

您是否分别定义了每个项目的大小?另外,在CollectionViewCell类中移动单元格布局的所有代码,而不是在cellForItemAt中编写所有代码。是否分别定义了每个项目的大小?另外,在CollectionViewCell类中移动单元格布局的所有代码,而不是在cellForItemAt中编写所有代码。感谢您的建议,但是“剪裁到边界”已经过检查,似乎没有任何影响。我会在答案区发布我的解决方案。谢谢你的建议,但“剪辑到边界”已经过检查,似乎没有任何影响。我会将我的解决方案张贴在回答区。