0
class ChatCollectionViewCell: UICollectionViewCell {

var chatView: UIView!
var chatTextView: UITextView!
var isTextFromCurrentUser: Bool = true
var chatViewWidth: CGFloat = 200

override init(frame: CGRect) {
    super.init(frame: frame)

    chatView = UIView()
    chatTextView = UITextView()
    contentView.addSubview(chatView)
    contentView.addSubview(chatTextView)

    setupViews()

}

override func layoutSubviews() {

    if isTextFromCurrentUser {
        chatView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true
        chatTextView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 15).isActive = true
        chatTextView.backgroundColor = .white
    } else {
        chatView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10).isActive = true
        chatTextView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -15).isActive = true
        chatTextView.backgroundColor = UIColor(r: 157, g: 255, b: 164)
    }

    chatView.widthAnchor.constraint(equalToConstant: chatViewWidth).isActive = true
    chatView.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
    chatTextView.widthAnchor.constraint(equalTo: chatView.widthAnchor, constant: -10).isActive = true
    chatTextView.topAnchor.constraint(equalTo: chatView.topAnchor, constant: 5).isActive = true

    chatView.translatesAutoresizingMaskIntoConstraints = false
    chatTextView.translatesAutoresizingMaskIntoConstraints = false

}

func setupViews() {

    chatView.backgroundColor = .blue

    chatTextView.font = UIFont.systemFont(ofSize: 16)
    chatTextView.layer.cornerRadius = 9
    chatTextView.clipsToBounds = true
    chatTextView.isScrollEnabled = false

}

override func prepareForReuse() {
    super.prepareForReuse()
    chatView = nil
    chatTextView = nil

    chatView = UIView()
    chatTextView = UITextView()
}

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

}

(for clarification, I am setting the chatViewWidth and the chatTextView.text property in the ViewController's cellForRow method)

So right now, the error that XCode is giving is the following: "Unable to activate constraint with anchors and because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies?"

I looked through many posts regarding common ancestor errors on StackOverflow, but none of the solutions solved my problem.

Which is very confusing. I tried using breakpoints to analyze what was wrong, but the program crashed after creating around ~14 cells or so. And sometimes it works, but when I add more cells, it will begin crashing. I'm not sure what the issue is--my views are definitely children views of the CollectionViewCell, correct?

Thank you!

chemo
  • 163
  • 2
  • 3
  • 9
  • You recreate the views in prepareForReuse but you don't add the new ones as subviews. – Craig Siemens Aug 30 '17 at 18:56
  • 1. You setting the constraints to self instead of the superview from the chatView. Means you added them to the contentView of the cell. 2. LayoutSubviews is called very much times if iam not wrong, why dont you set the constraints on setupViews? 3. LayoutSubviews does not call super.layoutSubviews, this could bring some problemns. Try putting a print in layoutSubviews, then it should appear much times if iam not wrong – Björn Ro Aug 30 '17 at 19:18
  • if you want to use prepareForReuse, than suggest clearing the content of the models, instead of removing them. After this you call setupViews again and set the constraints. When you set „isTextFromCurrentUser“ than you can call a didSet method on the property and change the constraints. – Björn Ro Aug 30 '17 at 19:24
  • oh and if iam not wrong, you need to remove the old constraints when these are not needed anymore. – Björn Ro Aug 30 '17 at 19:25
  • Hmm.. So I tried everything in the comments. @CleverError your solution doesn't throw an error, but it messed up the spacing between the cells. – chemo Aug 30 '17 at 19:59
  • @Bj, Shouldn't I be setting the constraints to the contentView, not the superview?. And yes! LayoutSubviews seems to be getting called many times, but if I do not set up my constraints there, the view doesn't get set up properly. How should I go about removing the constraints/content of the old cells? – chemo Aug 30 '17 at 20:02
  • @chemo ah sorry, i ment that you setting the constraints to the cellView instead of the contentView. Is the cell changing its layout all the time? Is there skmething special on your setup for the CollectionView or CollectionViewLayout? – Björn Ro Aug 31 '17 at 05:03
  • @Bj, there aren't any special settings for my CollectionViewFlowLayout. It's the instance of the base UICollectionViewFlowLayout class. I'm confused though, because what would the difference between setting my anchors to the cellView instead of the contentView? When I call self.rightAnchor in my CollectionViewCell class, am I not calling the cellView? – chemo Aug 31 '17 at 14:21
  • @Bjorn By the way, thank you so much for your help. Truly appreciate it. – chemo Aug 31 '17 at 14:22
  • @chemo iam not sure if it makes a different to set the anchors to the contentView or cellView. It juste makes more sense, because you should try to set the anchor to its superView. The superView of the cahtView and chatTextView is the contentView. Maybe you should sort up the code. I will try to sort it. And put in in a answer – Björn Ro Aug 31 '17 at 17:54
  • Sorry, today i got no time. What about trying at first only the text to the left side. So move the constraints out of layoutSubviews, just add them in the init function at first. In prepareForReuse you dont set the views to nil, you clear them. Means set text to Empty etc. than you should work. If yes, than try changing the constraint that is needed for the left and right thing. Store the Constraint for each of them, and activate and deactivate the ones needed and not. Would be cool if you post the state after this and than i can reply :) Happy Coding – Björn Ro Aug 31 '17 at 17:59

1 Answers1

0

This is how i would do it ... well basicy i would set all the stuff in Storyboard and set an Outlet for the widthConstraint ... but to take your code, this should work. But its not testet ... :)

class ChatCollectionViewCell: UICollectionViewCell {

    var chatView: UIView!
    var chatTextView: UITextView!
    var isTextFromCurrentUser: Bool = true {
        didSet {
            if isTextFromCurrentUser {
                NSLayoutConstraint.deactivate(rightAlignmentConstraints)
                NSLayoutConstraint.activate(leftAlignmentConstraints)
                chatTextView.backgroundColor = .white

            } else {
                NSLayoutConstraint.deactivate(leftAlignmentConstraints)
                NSLayoutConstraint.activate(rightAlignmentConstraints)

                chatTextView.backgroundColor = UIColor(r: 157, g: 255, b: 164)
            }
        }
    }
    var chatViewWidth: CGFloat = 200 {
        didSet {
            chatView.widthAnchor.constraint(equalToConstant: chatViewWidth).isActive = true
        }
    }

    private var leftAlignmentConstraints: [NSLayoutConstraint] = []
    private var rightAlignmentConstraints: [NSLayoutConstraint] = []

    override init(frame: CGRect) {
        super.init(frame: frame)

        setupViews()

    }

    func setupViews() {

        chatView = UIView()
        chatTextView = UITextView()
        contentView.addSubview(chatView)
        contentView.addSubview(chatTextView)

        chatView.translatesAutoresizingMaskIntoConstraints = false
        chatTextView.translatesAutoresizingMaskIntoConstraints = false

        chatView.backgroundColor = .blue

        chatTextView.font = UIFont.systemFont(ofSize: 16)
        chatTextView.layer.cornerRadius = 9
        chatTextView.clipsToBounds = true
        chatTextView.isScrollEnabled = false

        leftAlignmentConstraints = [
            chatView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10),
            chatTextView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 15)
        ]

        rightAlignmentConstraints = [
            chatView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10),
            chatTextView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -15)
        ]

        chatView.widthAnchor.constraint(equalToConstant: chatViewWidth).isActive = true
        chatView.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
        chatTextView.widthAnchor.constraint(equalTo: chatView.widthAnchor, constant: -10).isActive = true
        chatTextView.topAnchor.constraint(equalTo: chatView.topAnchor, constant: 5).isActive = true

        NSLayoutConstraint.activate(leftAlignmentConstraints)
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        chatTextView.text = ""

    }

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

Good Luck and Happy Coding

Björn Ro
  • 780
  • 3
  • 9