【问题标题】:Weird bug returning a CGSize in UICollectionView sizeForItemAtIndexPath在 UICollectionView sizeForItemAtIndexPath 中返回 CGSize 的奇怪错误
【发布时间】:2017-04-07 22:19:26
【问题描述】:

我的 UICollectionView 和 sizeForItemAtIndexPath 函数中有可变宽度,我最终返回 CGSize

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    var width: CGFloat = indexPath.row == 0 ? 37 : 20 // default paddings based on spacing in cell
    let font = UIFont.systemFont(ofSize: 14, weight: UIFontWeightRegular)

    if indexPath.row == 0 {
        width += listingsFilter.stringValue.width(withConstrainedHeight: 28, font: font)
    } else {
        let string = viewModel.valueRangeForButton[indexPath.row - 1]
        width += string.width(withConstrainedHeight: 28, font: font)
    }

    print(width) // some decimal e.g. 138.1239581
    let w: CGFloat = width.rounded() // rounded e.g. 13

    return CGSize(width: w, height: 28)
}

如果我使用宽度数字(例如 128)存根返回值,而不是使用变量,则集合视图尊重 UIEdgeInsets。如果我返回带有宽度变量的 CGSize,则除了第一个和最后一个元素之外,UIEdgeInsets 将被忽略。

我觉得我发现了一些很深的 CoreGraphics 错误。

对于最后两行,如果我将它们更改为

let x: CGFloat = 128 // or 128.0, doesn't matter
return CGSize(width: x, height: 28)

还是不行。我尝试使用 Int 初始化程序返回 CGSize。我已经尝试转换为 Ints 并返回到 CGFloats。似乎没有任何效果。

我已将问题范围缩小到这一点。它与它上面的width 代码(这是一个字符串扩展名)或其他任何东西没有任何关系。

超级奇怪。有人有这方面的经验吗?

编辑:一些图片

顶部是CGSize(width: w, height: 28),其中wCGFloat,可以等于128 或任何其他值。底部是CGSize(width: 128, height: 28)

【问题讨论】:

  • 评论中的意思是e.g. 138
  • 呃!我知道这个问题,但我不记得解决方案......我会在我知道的时候回来找你!但是一个解决方案:)
  • @alistra 任何数字,无论是 int 还是 cgfloat
  • @HAS 再保证!期待回音
  • 我正在尝试在每个集合视图单元格中实现与文本和潜在图像相对应的宽度,顶部和底部插入 15pt,集合视图单元格之间插入 10pt

标签: swift uicollectionview


【解决方案1】:

几个月前我遇到了类似的问题。据我记得,试图解决这个问题(就像你的情况一样)真的很烦人,但非常简单。
你需要确保你的类继承自 UICollectionViewDelegateFlowLayout。它继承自UICollectionViewDelegate。那应该是诀窍。
让我知道这是否适合你。

【讨论】:

  • 它已经继承自它。我原帖中的代码来自UICollectionViewDelegateFlowLayout 中的委托函数
【解决方案2】:

我可以从 op 的问题中理解

在单元格中移动你需要的内容

func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout:
    UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    return UIEdgeInsets(top: 15, left: 0, bottom: 15, right: 0)
}

在您需要的各个单元格之间移动空格

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
{
    return 15
}

一定要面对委托 UICollectionViewDelegateFlowLayout

【讨论】:

  • 不幸的是,这不是它。该问题指出,返回带有width 的数字的CGSize 计算并存储在变量中并传递给CGSize init 会导致与传递给CGSize init 的硬编码CGFloat 不同的行为。
  • 这不是您评论的内容--->“我正在尝试在每个集合视图单元格中实现与文本和潜在图像相对应的宽度,顶部和底部插入 15pt,集合视图单元格之间插入 10pt – 扎克夏皮罗昨天”
  • 是的,但我仍然需要为每个需要点击sizeForItem 函数的单元格获取不同的宽度返回此错误
【解决方案3】:

从未尝试从sizeForItemAtIndexPath() 返回硬编码值而不是变量,我一直认为UIEdgeInsets 甚至不应该影响UICollectionView 的单元格之间的间距,但只是围绕整个细胞部分的空间。看起来UIEdgeInsets 并非旨在影响单元格之间的间距,在这种情况下,Apple 的错误与它看起来的相反——UIEdgeInsets 在一个异常情况下奇怪地影响了单元格之间的间距,当事实上,它从未打算在任何情况下这样做。这条红鲱鱼让您合理地假设必须有一种可靠且程序化的方式来让UIEdgeInsets 设置UICollectionView 单元格之间的间距。我还没有找到一种程序化的方式来做到这一点。当我找到以下故事板解决方案时,我不再寻找。

在花费大量时间调整UICollectionViews 以使它们看起来像我想要的样子之后,我发现设置单元格之间间距的唯一可靠方法是使用情节提要设置,如下所示:

在情节提要中,选择您的UICollectionView,转到属性检查器,找到“最小间距”部分,然后在“单元格”框中输入您想要的值(在您的情况下为 10)。 “对于单元格”值是单元格之间的水平间距。对“For Lines”值执行相同操作,即单元格之间的垂直间距。

【讨论】:

    【解决方案4】:

    请检查下面的代码,

    class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        collectionView?.delegate = self
        collectionView?.contentInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    
        let x: CGFloat = 50 + CGFloat(arc4random_uniform(50)) // or 128.0, doesn't matter
        return CGSize(width: x, height: 28)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 15, left: 0, bottom: 15, right: 0)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
    {
        return 15
    }
    
    
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 50
    }
    
    
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        return collectionView.dequeueReusableCell(withReuseIdentifier: "aaa", for: indexPath)
    }
    
    
    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    

    }

    结果是

    【讨论】:

      【解决方案5】:

      它与UIEdgeInsets 无关,它与您在代码中计算的width 相关。当您设置width: 128 时,为您的单元格提供的宽度大于它们实际需要的宽度(比如说90),因此根据您的UICollectionViewCell 的设计,它可能感觉 UIEdgeInsets 对应每个单元格。

      解决您的问题:

      如果你使用的是IB,你可以在IB中设置cellSpacinglineSpacing,否则你必须实现UICollectionViewDelegateFlowLayout

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-16
        • 1970-01-01
        • 1970-01-01
        • 2020-03-26
        • 2016-03-14
        相关资源
        最近更新 更多