Should the contentView.translatesAutoResizingMaskToConstraints of a UICollectionViewCell subclass be set to `false`?

走远了吗. 提交于 2019-12-01 17:04:56
Senseful

After testing things out, I noticed at least one reason to keep contentView.translatesAutoresizingMaskToConstraints = true.

If you use preferredLayoutAttributesFittingAttributes(_:) to alter the dimensions of a UICollectionViewCell, it works by sizing the contentView to the correct dimension. If you set contentView.translatesAutoresizingMaskToConstraints = false, you'll lose this functionality.

Therefore, I recommend using Solution 1 (altering at least one constraint in each dimension to be non-required). In fact, I created a wrapper for UICollectionViewCell that will handle both the required 999 constraint, and a way to get preferred height or width to function correctly.

By using this wrapper, you won't need to remember the intricacies of getting the contentView in a UICollectionViewCell to behave properly.


class CollectionViewCell<T where T: UIView>: UICollectionViewCell {

  override init(frame: CGRect) {
    preferredHeight = nil
    preferredWidth = nil

    super.init(frame: frame)
  }

  var preferredWidth: CGFloat?
  var preferredHeight: CGFloat?
  private(set) var view: T?

  func initializeView(view: T) {
    assert(self.view == nil)
    self.view = view

    contentView.addSubview(view)

    view.translatesAutoresizingMaskIntoConstraints = false

    var constraint: NSLayoutConstraint

    constraint = NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal, toItem: contentView, attribute: .Top, multiplier: 1, constant: 0)
    constraint.active = true
    constraint = NSLayoutConstraint(item: view, attribute: .Leading, relatedBy: .Equal, toItem: contentView, attribute: .Leading, multiplier: 1, constant: 0)
    constraint.active = true

    // Priority must be less than 1000 to prevent errors when installing
    // constraints in conjunction with the contentView's autoresizing constraints.
    let NonRequiredPriority: UILayoutPriority = UILayoutPriorityRequired - 1

    constraint = NSLayoutConstraint(item: view, attribute: .Bottom, relatedBy: .Equal, toItem: contentView, attribute: .Bottom, multiplier: 1, constant: 0)
    constraint.priority = NonRequiredPriority
    constraint.active = true
    constraint = NSLayoutConstraint(item: view, attribute: .Trailing, relatedBy: .Equal, toItem: contentView, attribute: .Trailing, multiplier: 1, constant: 0)
    constraint.priority = NonRequiredPriority
    constraint.active = true
  }

  override func preferredLayoutAttributesFittingAttributes(layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    let newLayoutAttributes = super.preferredLayoutAttributesFittingAttributes(layoutAttributes)

    if let preferredHeight = preferredHeight {
      newLayoutAttributes.bounds.size.height = preferredHeight
    }
    if let preferredWidth = preferredWidth {
      newLayoutAttributes.bounds.size.width = preferredWidth
    }

    return newLayoutAttributes
  }
}

(Note: the init method is required due to a bug with generic subclasses of UICollectionViewCell.)

To register:

collectionView.registerClass(CollectionViewCell<UIView>.self, forCellWithReuseIdentifier: "Cell")

To use:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CollectionViewCell<UILabel>

  if cell.view == nil {
    cell.initializeView(UILabel())
  }

  cell.view!.text = "Content"
  cell.preferredHeight = collectionView.bounds.height

  return cell
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!