创建UICollectionViewCell时子视图帧不正确

Fel*_*rri 36 xcode ios uicollectionview uicollectionviewcell swift

问题

我创建了一个带有自定义UICollectionViewCell的UICollectionViewController.自定义单元格包含一个大的矩形UIView(名为colorView)和一个UILabel(名为nameLabel).

首次使用单元格填充集合并打印colorView.frame时,打印的帧具有不正确的值.我知道它们是不正确的,因为colorView帧大于单元框架本身,即使colorView被正确绘制.

但是,如果我滚动collectView足以触发重用以前创建的单元格,colorView.frame现在具有正确的值!我需要正确的帧,因为我想将圆角应用于colorView图层,我需要正确的coloView大小才能执行此操作.顺便说一下,如果你想知道,colorView.bounds也有与colorView.frame相同的错误大小值.

这个问题

创建单元格时为什么帧不正确?

现在一些代码

这是我的UICollectionViewCell:

class BugCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var colorView: UIView!
    @IBOutlet weak var nameLabel: UILabel!
}
Run Code Online (Sandbox Code Playgroud)

这是UICollectionViewController:

import UIKit

let reuseIdentifier = "Cell"
let colors = [UIColor.redColor(), UIColor.blueColor(),
              UIColor.greenColor(), UIColor.purpleColor()]
let labels = ["red", "blue", "green", "purple"]

class BugCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return colors.count
    }

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as BugCollectionViewCell

        println("ColorView frame: \(cell.colorView.frame) Cell frame: \(cell.frame)")

        cell.colorView.backgroundColor = colors[indexPath.row]
        cell.nameLabel.text = labels[indexPath.row]

        return cell
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        let width = self.collectionView?.frame.width
        let height = self.collectionView?.frame.height
        return CGSizeMake(width!, height!/2)
    }
}
Run Code Online (Sandbox Code Playgroud)

设置集合视图是为了一次显示两个单元格,每个单元格包含一个涂有颜色的大矩形和一个带有颜色名称的标签.

当我在模拟器上运行上面的代码时,我得到以下打印结果:

ColorView frame: (0.0,0.0,320.0,568.0) Cell frame: (0.0,0.0,375.0,333.5)
ColorView frame: (0.0,0.0,320.0,568.0) Cell frame: (0.0,343.5,375.0,333.5)
Run Code Online (Sandbox Code Playgroud)

这是一个奇怪的结果 - colorView.frame的高度为568点,而单元格框架的高度仅为333.5点.

如果我向下拖动collectionView并重新使用单元格,则会打印以下结果:

ColorView frame: (8.0,8.0,359.0,294.0) Cell frame: (0.0,1030.5,375.0,333.5)
ColorView frame: (8.0,8.0,359.0,294.0) Cell frame: (0.0,343.5,375.0,333.5)
Run Code Online (Sandbox Code Playgroud)

我无法理解的东西沿着纠正colorView框架的方式发生.

我认为这与从Nib加载单元格的事实有关,因此控制器不使用init(frame:frame)初始化程序,而是使用init(编码器:aCoder)初始化程序,因此只要单元格是创建它可能带有一些我无法编​​辑的默认框架.

我会感激任何帮助我了解正在发生的事情的帮助!

我正在使用Xcode 6.1.1.使用iOS SDK 8.1.

Jon*_*gel 61

您可以通过覆盖自定义Cell类中的layoutIfNeeded()来获取单元格的最终帧,如下所示:

override func layoutIfNeeded() {
    super.layoutIfNeeded()
    self.subView.layer.cornerRadius = self.subView.bounds.width / 2
}
Run Code Online (Sandbox Code Playgroud)

然后在你的UICollectionView数据源方法cellForRowAtIndexPath中:执行以下操作:

let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CustomCollectionViewCell
cell.setNeedsLayout()
cell.layoutIfNeeded()
Run Code Online (Sandbox Code Playgroud)

  • 这里的第一个代码示例最终是真正的答案.谢谢. (3认同)

Rya*_*anG 17

UICollectionViewCell使用自动布局约束我遇到了同样的问题.

layoutIfNeeded在配置依赖于视图框架宽度的子视图之前,我不得不打电话.

  • 你究竟在哪里调用layoutIfNeeded?我记得我曾尝试在视图控制器init上调用它,但它没有工作,好像在执行自动布局之前已经加载了单元格,即使在使用layoutIfNeeded进行排队之后... (2认同)

Fel*_*rri 8

好的,我现在明白了在自动布局定义框架之前创建了单元格.这就是为什么在创建时刻限是错误的.当重复使用这些单元时,帧已经被纠正.

在创建自定义UIView时,我遇到了这个问题,该UIView将某些图层和子视图放在特定坐标中.当创建这个UIView的实例时,子视图的放置都是错误的(因为自动布局还没有开始).

我发现不必配置视图子视图,init(coder: aCoder)我必须覆盖该方法layoutSubviews().当自动布局要求每个视图布置自己的子视图时调用此方法,因此此时至少父视图具有正确的框架,我可以使用它来正确放置子视图.

可能如果我在自定义视图代码上使用了约束而不是自己处理帧大小和定位,那么布局就可以正确完成,并且没有必要覆盖layoutSubviews().


Vad*_*vin 8

iOS 10,Swift 3.0.1中使用Core Graphics绘图存在此问题.

将此方法添加到UICollectionView子类:

override func didMoveToSuperview() {
    super.didMoveToSuperview()
    setNeedsLayout()
    layoutIfNeeded()
}
Run Code Online (Sandbox Code Playgroud)

我的问题是核心图形形状没有正确计算,因为layoutSubviews()没有调用.