我尝试使用 UICollectionViewFlowLayout 设置 UICollectionView ,并满足以下要求: minimumLineSpacing 应该始终是一个 - UICollectionView 的高度的三分之一。我最初的想法是覆盖 viewDidLayoutSubviews ,如下所示:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionViewFlowLayout.minimumLineSpacing = collectionView.frame.height / 3
collectionViewFlowLayout.invalidateLayout()
}
请注意,我使用 viewDidLayoutSubviews ,因为我计划使用自动布局,框架可能依赖于某些复杂的约束。所以我无法自己计算帧数,但必须等到自动布局计算出它才能在 viewDidLayoutSubviews 中使用。
我通过以编程方式创建 UICollectionView 来测试这一点(并旋转模拟器以查看 minimumLineSpacing 是否始终正确)。它似乎工作得很好。
然后,我切换到自动布局。我只是简单地将集合视图的顶部,底部,前导和尾随空间限制在其超级视图中。在这样做之后,设置 minimumLineSpacing 不再具有预期的效果,它根本没有改变集合视图的外观。
以下代码很好地演示了该问题。只要我将useAutoLayout
设置为true
,设置 minimumLineSpacing 就不再有用了。
class DemoViewController: UIViewController, UICollectionViewDataSource {
var collectionView: UICollectionView!
var collectionViewFlowLayout: UICollectionViewFlowLayout!
// MARK: - UIViewController
override func viewDidLoad() {
super.viewDidLoad()
collectionViewFlowLayout = UICollectionViewFlowLayout()
collectionViewFlowLayout.itemSize = CGSizeMake(100, 100)
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: collectionViewFlowLayout)
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
collectionView.dataSource = self
view.addSubview(collectionView)
let useAutoLayout = false // Change this to true to test!
if useAutoLayout {
collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[collectionView]-|", options: nil, metrics: nil, views: ["collectionView" : collectionView]))
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[collectionView]-|", options: nil, metrics: nil, views: ["collectionView" : collectionView]))
} else {
collectionView.autoresizingMask = .FlexibleHeight | .FlexibleWidth
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionViewFlowLayout.minimumLineSpacing = collectionView.frame.height / 3
collectionViewFlowLayout.invalidateLayout()
}
// MARK: - <UICollectionViewDataSource>
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! UICollectionViewCell
cell.backgroundColor = UIColor.greenColor()
return cell
}
}
在模拟器中测试此代码,旋转它,看看当useAutoLayout
设置为true
时如何设置 minimumLineSpacing 不做任何事情。所以我的问题是:如何使用自动布局并仍然提供 minimumLineSpacing ?
备注
Base SDK 设置为 iOS 8.4 SDK 。设置itemSize
或minimumInteritemSpacing
等其他属性也不起作用。
答案 0 :(得分:1)
我已经复制了你描述的内容。这很奇怪。
我认为有一些关于轮换的内容会导致invalidLayout()
在此上下文中被忽略。也许问题是你对invalidateLayout()
的调用发生在布局对象认为它已经响应或正在响应的点上,因为旋转自动产生的布局失效以及随后的边界变化。集合视图。然后忽略您的失效,因为它被合并到自动失效中为时已晚,而且太早被视为单独的失效。我在猜测。我注意到你甚至可以继续增加minimumLineSpacing
那里,并且它会愉快地进入无限,而集合视图没有机智再次进行布局。
但如果您设置视图控制器以使震动事件触发失效,则会注意到该值。
因此,您可以通过强制在运行循环的下一轮发生无效来解决问题,从而避免在旋转期间阻止它的任何奇怪的特殊逻辑。例如,如果您使用以下内容替换viewDidLayoutSubviews()
:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let newValue = collectionView.bounds.height / 3
dispatch_async(dispatch_get_main_queue()) {
[weak collectionViewFlowLayout] in
collectionViewFlowLayout?.minimumLineSpacing = newValue
}
然后它有效。
为什么这是必要的?我不知道。我不认为这是必要的。这感觉就像UICollectionView
中的一个错误,或者至少是一个非常不直观的API。