问题
我创建了一个带有自定义UICollectionViewCell的UICollectionViewController。 自定义单元格包含一个大的矩形UIView(名为colorView)和一个UILabel(名为nameLabel)。
首次使用单元格填充集合并打印colorView.frame时,打印的帧具有不正确的值。我知道它们是不正确的,因为colorView帧大于单元框架本身,即使colorView被正确绘制。
但是,如果我滚动collectionView足以触发重复使用先前创建的单元格,则colorView.frame现在具有正确的值! 我需要正确的帧,因为我想将圆角应用于colorView图层,我需要正确的coloView大小才能执行此操作。 顺便说一句,如果你想知道,colorView.bounds也有与colorView.frame相同的错误大小值。
问题
创建单元格时,为什么帧不正确?
现在有些代码
这是我的UICollectionViewCell:
class BugCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var colorView: UIView!
@IBOutlet weak var nameLabel: UILabel!
}
这是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)
}
}
设置集合视图是为了一次显示两个单元格,每个单元格包含一个涂有颜色的大矩形和一个带有颜色名称的标签。
当我在模拟器上运行上面的代码时,我得到以下打印结果:
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)
这是一个奇怪的结果 - 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)
我无法理解的东西沿着纠正colorView框架的方式发生。
我认为这与从Nib加载单元格的事实有关,因此控制器使用init(编码器:aCoder)初始化程序而不是使用init(frame:frame)初始化程序,所以尽快创建单元格它可能带有一些我无法编辑的默认框架。
我会感谢任何帮助我了解正在发生的事情的帮助!
我正在使用Xcode 6.1.1。使用iOS SDK 8.1。
答案 0 :(得分:55)
您可以通过覆盖自定义Cell类中的layoutIfNeeded()来获取单元格的最终帧,如下所示:
private function ShowPosts($ps)
{
$GLOBALS['psvalue'] = $ps;
echo '<hr />';
add_filter('parse_query', function() {
$ps = $GLOBALS['psvalue'];
global $query, $pagenow, $post_type;
if($pagenow == 'edit.php' && $post_type == 'post'){
$query->query_vars['post__in'] = $ps;
}
});
}
然后在你的UICollectionView数据源方法cellForRowAtIndexPath中:执行此操作:
override func layoutIfNeeded() {
super.layoutIfNeeded()
self.subView.layer.cornerRadius = self.subView.bounds.width / 2
}
答案 1 :(得分:16)
我使用自动布局限制UICollectionViewCell
遇到了同样的问题。
在配置依赖于视图框架宽度的子视图之前,我不得不调用layoutIfNeeded
。
答案 2 :(得分:8)
好的,我现在明白了在自动布局定义框架之前创建了单元格。这就是为什么在创建时刻限是错误的。当重复使用单元格时,帧已经被纠正。
我在创建自定义UIView时出现此问题,该UIView将某些图层和子视图放置在特定坐标中。当创建这个UIView的实例时,子视图的放置都是错误的(因为自动布局还没有开始)。
我发现不是在init(coder: aCoder)
上配置视图子视图,而是必须覆盖方法layoutSubviews()
。当自动布局要求每个视图布置自己的子视图时调用此方法,因此此时至少父视图具有正确的框架,我可以使用它来正确放置子视图。
如果我在自定义视图代码上使用了约束而不是处理帧大小和定位,那么布局可能已经正确完成,并且不必覆盖layoutSubviews()
。
答案 3 :(得分:8)
在 iOS 10,Swift 3.0.1 中使用Core Graphics绘图存在此问题。
将此方法添加到UICollectionView
子类:
override func didMoveToSuperview() {
super.didMoveToSuperview()
setNeedsLayout()
layoutIfNeeded()
}
我的问题是核心图形形状没有正确计算,因为没有调用layoutSubviews()
。
答案 4 :(得分:0)
我建议为您正在做的任何事情创建一个子类。我需要在我的单元格中的 UIImageView 上设置渐变,但它计算错误。我尝试了 layoutSubviews 的建议,但它也导致了问题,它似乎会应用渐变两次。
我创建了一个 UIImageView 子类,它可以正常工作。
class MyOwnImageView: UIImageView{
override func layoutSubviews() {
super.layoutSubviews()
let view = UIView(frame: frame)
let width = bounds.width
let height = bounds.height
let sHeight:CGFloat = 122.0
let shadow = UIColor.black.withAlphaComponent(0.9).cgColor
let topImageGradient = CAGradientLayer()
topImageGradient.frame = CGRect(x: 0, y: 0, width: width, height: sHeight)
topImageGradient.colors = [shadow, UIColor.clear.cgColor]
view.layer.insertSublayer(topImageGradient, at: 0)
let bottomImageGradient = CAGradientLayer()
bottomImageGradient.frame = CGRect(x: 0, y: height - sHeight, width: width, height: sHeight)
bottomImageGradient.colors = [UIColor.clear.cgColor, shadow]
view.layer.insertSublayer(bottomImageGradient, at: 0)
addSubview(view)
bringSubviewToFront(view)
}
}