【问题标题】:iOS swift UICollectionView loses cell constraints after scrolling past first screen fulliOS swift UICollectionView在滚动超过第一个屏幕后失去单元格约束
【发布时间】:2019-10-24 14:30:08
【问题描述】:

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

然后当它通过第 11 个项目时,我向下滚动,它似乎完全失去了它的布局,如下图所示。向上滚动,更奇怪的是,所有的单元格都变成了全尺寸的图像。

Example in simulator

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

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.

问题是,以前的细胞都是好的。

附加代码:

CollectionViewCell.swift


import UIKit


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


}


ViewController.swift


import UIKit


class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {


    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 25
    }


    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
        cell.cellImage.image = UIImage(named: "file-35")
        cell.cellLabel.text = "cell# \(indexPath.item)"


        cell.layer.borderWidth = 0.5
        cell.layer.borderColor = UIColor.lightGray.cgColor
        cell.layer.cornerRadius = 10


        cell.backgroundColor = UIColor.black
        cell.cellImage.layer.cornerRadius = 10


        print("indexPath.item: \(indexPath.item)")
        print("view.bounds: \(view.bounds)")
        print("collectionView.bounds: \(collectionView.bounds)")
        print("collectionView.contentInset: \(collectionView.contentInset)")
        print("collectionView.alignmentRectInsets: \(collectionView.alignmentRectInsets)")


        print("layoutAttributesForItem: \(String(describing: collectionView.layoutAttributesForItem(at: indexPath)))")


        return cell
    }




    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        collectionView.delegate = self
        collectionView.dataSource = self
//        view.translatesAutoresizingMaskIntoConstraints = true
    }

顺便说一句,使用哪个版本的运行时模拟器似乎没有任何区别。

非常感谢任何帮助、指示、建议等,而我还有一些头发要拔掉。谢谢。

【问题讨论】:

  • 您是否分别定义了每个项目的大小?另外,将单元格布局的所有代码移动到 CollectionViewCell 类中,而不是在 cellForItemAt 中编写所有内容。

标签: ios swift uicollectionview


【解决方案1】:

尝试将CollectionViewCell内的cellImageclipToBounds属性设置为true,即

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

    override func awakeFromNib() {
        super.awakeFromNib()
        self.cellImage.clipsToBounds = true //here..
    }
    //rest of the code....
}

您也可以在 UI 本身中设置cellImageclipToBounds,即

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

【讨论】:

  • 感谢您的建议,但 Clip to Bounds 已经过检查,似乎没有任何影响。我会在回答区发布我的解决方案。
【解决方案2】:

感谢您的建议。我发现一篇 Stack Overflow 文章将我推向了似乎有助于解决问题的方向。

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

使用调试器观察,sizeForItemAt() 仅在最初被调用,而不是在开始重用单元格时调用,当单元格大小丢失时,各种不受欢迎的事情开始发生。

在 viewDidLoad() 中初始化单元格大小消除了大部分问题,即在设备旋转之前,然后在 iPhone 模拟器中调用 sizeForItemAt() 以获取新布局,但在 iPad 模拟器中不调用。

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

这似乎已经解决了问题,至少目前是这样。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多