UICollectionViewCell - 不同尺寸的不同布局 类

UICollectionViewCell - different layout for different size classes

我有一个简单的 UICollectionViewCell,其中包含一张图片和一个标签。在常规尺寸 class 中,我希望图像位于顶部,标签位于其下方。这是 Xcode 的预览选项卡中的样子:

任何其他尺寸 class 我希望图像在左侧,标签在右侧:

我这样设置约束:

ImageView 具有以下约束:

标签有以下限制:

我还实现了return基于当前特征集合的不同单元格大小的方法:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    if (traitCollection.horizontalSizeClass == .Regular) {
      return CGSizeMake(240, 194)
    }
    else {
      return CGSizeMake(340, 128)
    }
  }

单元格在预览中看起来很好,当我 运行 它在 iPhone 上时一切正常(例如 Compact-Regular)。但是,当我 运行 它在 iPad:

时自动布局中断

当然,我在调试控制台中收到了一堆警告:无法同时满足约束条件。

所以,我想问题是 - 为不同大小 classes 设置单元格的正确方法是什么?

我用 demo project

创建了一个 github 仓库

谢谢!

这可能不是最优雅的解决方案,但我过去尝试这样做会导致自动布局尺寸 classes 更加痛苦,我发现最好的解决方案是:

  1. 每个尺寸都有一个单独的笔尖 class,然后根据需要在每个尺寸中布置视图。
  2. 每个尺寸 class 有单独的 CollectionViewFlowLayouts,然后在尺寸变化时在它们之间过渡。

遵循此模式,单元格大小将由 collectionViewFlowlayout 而不是 sizeForItem... 确定,您将更好地控制其他参数,例如 sectionInsetminimumLineSpacing等在集合视图中更改大小时通常需要变化 classes。

以下是对我有用的代码更改:

  let cellIdentifierCompact = "CustomCellCompact"
  let cellIdentifierRegular = "CustomCellReg"

  lazy var compactLayout: UICollectionViewFlowLayout = {
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSizeMake(240, 194)
    return layout
  }()

lazy var regLayout: UICollectionViewFlowLayout = {
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSizeMake(320, 128)
    return layout
  }()

override func viewDidLoad() {
    super.viewDidLoad()

    let customCellNib = UINib(nibName: cellIdentifierCompact, bundle: nil)
    self.collectionView.registerNib(customCellNib, forCellWithReuseIdentifier: cellIdentifierCompact)

    let customCellNibReg = UINib(nibName: cellIdentifierRegular, bundle: nil)
    self.collectionView.registerNib(customCellNibReg, forCellWithReuseIdentifier: cellIdentifierRegular)
    self.configureLayoutForSize()
  }


func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cellId = self.collectionView.collectionViewLayout == self.regLayout ? cellIdentifierRegular : cellIdentifierCompact
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId, forIndexPath: indexPath)
    return cell
  }

  func configureLayoutForSize(){
    switch self.traitCollection.horizontalSizeClass{
    case UIUserInterfaceSizeClass.Regular:
      self.collectionView.setCollectionViewLayout(self.regLayout, animated: false)
    case .Compact, .Unspecified:
      self.collectionView.setCollectionViewLayout(self.compactLayout, animated: false)
    }
  }

  override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    self.configureLayoutForSize()
    self.collectionView.reloadData()
  }

您想要做的是像您一样禁用常规尺寸 class 的那些约束,但同时将它们的优先级更改为 < 1000(即不需要)。这样,它将改为对特定大小 class.

使用更高优先级的约束