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

后端 未结 1 1167
礼貌的吻别
礼貌的吻别 2021-01-12 16:07

TL;DR

When trying to size UICollectionViewCells via auto layout, you can easily get auto layout warnings with even a simple example.

Should we be setting

相关标签:
1条回答
  • 2021-01-12 16:30

    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
    }
    
    0 讨论(0)
提交回复
热议问题