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

标签 ios cocoa-touch autolayout uicollectionview

我正在尝试设置一个带有 UICollectionViewFlowLayoutUICollectionView,并满足以下要求:minimumLineSpacing 应该始终正好是三分之一UICollectionView 的高度。我最初的想法是像这样覆盖 viewDidLayoutSubviews:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    collectionViewFlowLayout.minimumLineSpacing = collectionView.frame.height / 3
    collectionViewFlowLayout.invalidateLayout()
}

请注意,我使用 viewDidLayoutSubviews 是因为我打算使用自动布局,并且框架可能取决于一些复杂的约束。所以我无法自己计算框架,必须等到 Auto Layout 计算出来,我才能在 viewDidLayoutSubviews 中使用它。

我通过以编程方式创建 UICollectionView(并旋转模拟器以查看 minimumLineSpacing 是否始终正确)对此进行了一些测试。它似乎工作得很好。

然后,我切换到自动布局。我只是将 Collection View 的顶部、底部、前导和尾随空间限制到它的父 View 。这样做之后,设置 minimumLineSpacing 不再有预期的效果,它根本没有改变 Collection View 的外观。

下面的代码很好地演示了这个问题。一旦我将 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。设置其他属性,如 itemSizeminimumInteritemSpacing 也不起作用。

最佳答案

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

我认为在这种情况下,旋转会导致 invalidLayout() 被忽略。也许问题在于您对 invalidateLayout() 的调用发生在布局对象认为它已经响应或正在响应由旋转和自动产生的布局失效的位置 Collection View 的随之而来的边界变化。然后您的失效将被忽略,因为它来不及合并到自动失效中,而且太早无法算作单独的失效。我正在猜测。我注意到您甚至可以在那里继续递增 minimumLineSpacing,并且它会愉快地前进到无穷大,而无需 Collection View 再次进行布局。

但是如果您设置 View Controller 以便摇动事件触发失效,那么它会注意到该值。

因此,您可以通过强制在运行循环的下一轮发生失效来解决问题,从而避免在循环期间阻止它的任何奇怪的特殊逻辑。例如,如果您将 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。

关于ios - 使用自动布局时设置 UICollectionViewFlowLayout 的属性不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32127890/

相关文章:

ios - Unity iOS 构建应用程序大小太大(1.7 GB),比 Android 大 30 倍?

objective-c - 在 switch 语句中达到默认值后 EXC BAD ACCESS

ios - 当我的应用收到多个推送通知时会发生什么?

ios - 如何使用 Autolayout 在不同设备上保持 UIView 比率?

ios - 具有多个 View 的 ScrollView iOS Autolayout

ios - 如何从Facebook SDK获取accessToken

ios - 在 UICollectionViewCell 中处理 ScrollView 大小

ios - 使用 Swift 保存和加载高分

ios - 键盘出现时如何滚动 UIScrollView?

ios6 - iOS Autolayout 按比例调整 UIViews 的大小?