'Access view file from UICollectionViewListCell

I have a question about the UICollection view list's separatorLayoutGuide. I saw this article and understood I need to override the function updateConstraints() in order to update the separator layout guide. like this...

override func updateConstraints() {
  super.updateConstraints()

  separatorLayoutGuide.leadingAnchor.constraint(equalTo: otherView.leadingAnchor, constant: 0.0).isActive = true
}

I can see the tiny space between the cell's leading anchor and seprateguide's leading anchor like the image below and I want to fix it. (like the left side of the cell) enter image description here

The problem is, however, I created a custom collection view list cell using this article and cannot change the separatorLayoutGuide leading to the custom view's leading. I added the customListCell.separatorLayoutGuide.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true in order to position the leading of separatorLayoutGuide to the customView's leading, and I get the

"UILayoutGuide:0x2822d8b60'UICollectionViewListCellSeparatorLayoutGuide'.leading"> and <NSLayoutXAxisAnchor:0x280e9cac0 "ContentView:0x15960db90.leading"> because they have no common ancestor.  Does the constraint or its anchors reference items in different view hierarchies?  That's illegal.'

error. After I've done the research, I figured I didn't addSubview for the separatorLayoutGuide, but even if I add a subview to the custom view, the app crashes. Is there a way to change the separator guide's leading anchor when using the custom UIView?

class CustomListCell: UICollectionViewListCell {

    var item: TestItem?
    
    override func updateConfiguration(using state: UICellConfigurationState) {
        
        // Create new configuration object
        var newConfiguration = ContentConfiguration().updated(for: state)
        
            newConfiguration.name = item.name
            newConfiguration.state = item.state

        // Set content configuration
        contentConfiguration = newConfiguration
    }
}


struct ContentConfiguration: UIContentConfiguration, Hashable {
    
    var name: String?
    var state: String?
    
    func makeContentView() -> UIView & UIContentView {
        return ContentView(configuration: self)
    }
    
    func updated(for state: UIConfigurationState) -> Self {
        guard let state = state as? UICellConfigurationState else {
            return self
        }
        
        // Updater self based on the current state
        let updatedConfiguration = self
        if state.isSelected {
            print("is selected")
        } else {
            print("is deselected")
        }
        return updatedConfiguration
    }
}


class ContentView: UIView, UIContentView {

    let contentsView = UIView()
    let customListCell = CustomListCell()

    lazy var titleLabel: UILabel = {
        let label = UILabel()
        label.text = ""
        return label
    }()

    lazy var statusLabel: UILabel = {
        let label = UILabel()
        label.text = ""
        return label
    }()

    lazy var symbolImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    init(configuration: ContentConfiguration) {
          // Custom initializer implementation here.
        super.init(frame: .zero)
        setupAllViews()
        apply(configuration: configuration)
    }


    override func updateConstraints() {
        super.updateConstraints()
        customListCell.separatorLayoutGuide.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private var currentConfiguration: ContentConfiguration!
    var configuration: UIContentConfiguration {
        get {
            currentConfiguration
        }
        set {
            guard let newConfiguration = newValue as? ContentConfiguration else {
                return
            }

            apply(configuration: newConfiguration)
        }
    }

    func setupAllViews() {
        // add subviews and add constraints
    }

    func apply(configuration: ContentConfiguration) {

    }
}


Solution 1:[1]

by overriding updateConstraints in a UICollectionViewListCell subclass

Solution 2:[2]

In your code you have a customListCell instance variable which is not necessary. Also you should not add separatorLayoutGuide as a subview anywhere.

Try to access the cell's contentView:

override func updateConstraints() {
    super.updateConstraints()

    if let customView = cell.contentView as? ContentView {
      separatorLayoutGuide.leadingAnchor.constraint(equalTo: customView.leadingAnchor, constant: 0.0).isActive = true
    }
}

Like this you can access any subview in your ContentView.

Another question is: Is it necessary to create a new constraint every time updateConstraints is called? Are constraints from previous calls still there? According to the documentation of updateConstraints:

Your implementation must be as efficient as possible. Do not deactivate all your constraints, then reactivate the ones you need. Instead, your app must have some way of tracking your constraints, and validating them during each update pass. Only change items that need to be changed. During each update pass, you must ensure that you have the appropriate constraints for the app’s current state.

Therefore I suggest this approach:

class ContentView: UIView, UIContentView {
    var separatorConstraint: NSLayoutConstraint?
    func updateForCell(_ cell: CustomListCell) {
        if separatorConstraint == nil {
            separatorConstraint = cell.separatorLayoutGuide.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 30)
        }
        separatorConstraint?.isActive = true
    }
}

class CustomListCell: UICollectionViewListCell {
    ...
    override func updateConstraints() {
        super.updateConstraints()
        (contentView as? AlbumContentView)?.updateForCell(self)
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Brian
Solution 2