使用自动布局时,设置UICollectionViewFlowLayout的属性不起作用

我试图build立一个UICollectionViewUICollectionViewFlowLayout与以下要求: minimumLineSpacing应该总是正好UICollectionView的高度的三分之一 。 我最初的想法是重写viewDidLayoutSubviews像这样:

override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() collectionViewFlowLayout.minimumLineSpacing = collectionView.frame.height / 3 collectionViewFlowLayout.invalidateLayout() } 

请注意,我使用viewDidLayoutSubviews,因为我打算使用自动布局,框架可能取决于一些复杂的约束。 所以我不能自己计算框架,但必须等到自动布局计算出来让我在viewDidLayoutSubviews中使用。

我通过编程创build一个UICollectionView来testing这个(并且旋转模拟器来查看minimumLineSpacing是否总是正确的)。 它似乎工作得很好。

然后,我切换到自动布局。 我只是简单地将collections视图的顶部,底部,前后空间限制在其超级视图中。 这样做后,设置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 } } 

在模拟器中testing这个代码,旋转它,看看如何设置minimumLineSpacinguseAutoLayout设置为true时不会执行任何useAutoLayout 。 所以我的问题是:我怎样才能使用自动布局,仍然提供minimumLineSpacing

笔记
基础SDK被设置为iOS 8.4 SDK 。 设置itemSizeminimumInteritemSpacing等其他属性也不起作用。

我已经复制了你描述的内容。 这很奇怪。

我认为有一些特定的旋转,导致invalidLayout()在这种情况下被忽略。 也许问题在于你对invalidateLayout()调用发生在布局对象认为它已经响应或正在响应布局失效的地方,这个布局失效由集合视图的旋转和随后的边界改变而自动产生。 那么你的失效就会被忽略,因为来不及合并到自动失效,并且很快就被视为一个单独的失效。 我正在猜测。 我注意到,你甚至可以不断增加minimumLineSpacing ,并且它将会愉快地前进到无限,而不会有收集视图再次有机智的布局。

但是,如果您设置视图控制器,以便摇动事件触发无效,则会通知该值。

所以你可以通过在运行循环的下一个循环中强制失效来解决问题,从而逃避在旋转期间任何奇怪的特殊逻辑阻塞它。 例如,如果您将viewDidLayoutSubviews()replace为以下内容:

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() let newValue = collectionView.bounds.height / 3 dispatch_async(dispatch_get_main_queue()) { [weak collectionViewFlowLayout] in collectionViewFlowLayout?.minimumLineSpacing = newValue } 

那么它的工作。

为什么这是必要的? 我不知道。 我不认为这是必要的。 这感觉就像UICollectionView一个bug,或者至less是一个非常不直观的API。