Below you can see two posts, one with an image, and one without. I placed borders around the views to better understand what is happening. I want the posts without images to be sized smaller than images with posts. I attempted to do this by doing the following:
func setupViews() {
backgroundColor = UIColor.white
addSubview(titleLabel)
addSubview(iconImageView)
addSubview(messageTextView)
addSubview(messageImageView)
iconImageView.anchor(top: contentView.topAnchor,
leading: contentView.leadingAnchor,
bottom: nil, trailing: nil,
padding: .init(top: 0, left: 8, bottom: 0, right: 0), size: CGSize(width: 44, height: 44))
titleLabel.anchor(top: contentView.topAnchor,
leading: iconImageView.trailingAnchor,
bottom: nil, trailing: nil,
padding: .init(top: 12, left: 8, bottom: 0, right: 0))
messageTextView.anchor(top: titleLabel.bottomAnchor,
leading: contentView.leadingAnchor,
bottom: nil,
trailing: contentView.trailingAnchor,
padding: .init(top: 4, left: 10, bottom: 0, right: 10))
messageImageViewHeightConstraint = messageImageView.heightAnchor.constraint(equalToConstant: 200)
messageImageViewHeightConstraint.isActive = true
messageImageView.anchor(top: messageTextView.bottomAnchor,
leading: contentView.leadingAnchor,
bottom: contentView.bottomAnchor,
trailing: contentView.trailingAnchor,
padding: .init(top: 4, left: 10, bottom: 0, right: 10))
}
When the posts are loading, I set the messageImageViewHeightConstraint.constant = 0 if the post does not have an image (optionals). This works to collapse the imageView. Unfortunately as you can see the textView expands to cover the remaining space. I don't want this, I want the contentView's intrinsic size to shrink, and I just want the text to expand to meet the content's intrinsic size. How can I do this? Thank you in advance.
Edit: more code for reference
private let iconImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.layer.cornerRadius = 10
iv.translatesAutoresizingMaskIntoConstraints = false
iv.clipsToBounds = true
iv.layer.borderWidth = 1
return iv
}()
private let titleLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .black
label.layer.borderWidth = 1
return label
}()
private let messageTextView: UILabel = {
let labelView = UILabel()
labelView.numberOfLines = 0
labelView.translatesAutoresizingMaskIntoConstraints = false
labelView.font = UIFont.systemFont(ofSize: 14)
labelView.layer.borderWidth = 1
return labelView
}()
private let messageImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.layer.masksToBounds = true
imageView.layer.borderWidth = 1
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
Edit #2 After following suggestions, here is the new code:
var post: Post?{
didSet{
guard let post = post else {return}
// Adding user's name
let attributedText = NSMutableAttributedString(string: post.author.name + " → " + post.group.name, attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14)])
// Adding date and user's first name
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .short
attributedText.append(NSAttributedString(string: "\n" + dateFormatter.string(from: post.timeCreated), attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12), NSAttributedString.Key.foregroundColor: UIColor(r: 155/255, g: 161/255, b: 171/255)]))
// Increasing Spacing
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 4
attributedText.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedText.length))
titleLabel.attributedText = attributedText
// Setting profile image
iconImageView.setImage(for: post.author, setContentMode: .scaleAspectFit)
DispatchQueue.main.async {
self.setupTextAndImageSubviews()
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupDefaultViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupDefaultViews(){
backgroundColor = UIColor.white
addSubview(titleLabel)
addSubview(iconImageView)
iconImageView.anchor(top: contentView.topAnchor, leading: contentView.leadingAnchor, bottom: nil, trailing: nil, padding: .init(top: 0, left: 8, bottom: 0, right: 0), size: CGSize(width: 44, height: 44))
titleLabel.anchor(top: contentView.topAnchor, leading: iconImageView.trailingAnchor, bottom: nil, trailing: nil, padding: .init(top: 12, left: 8, bottom: 0, right: 0))
}
private func setupTextAndImageSubviews() {
addSubview(messageTextView)
var textViewBottomAnchor: NSLayoutYAxisAnchor? = contentView.bottomAnchor
if self.post?.messageImageURL != nil {
textViewBottomAnchor = nil // dont need to anchor text view to bottom if image exists
}
// Setting body text
messageTextView.text = self.post?.body
messageTextView.anchor(top: titleLabel.bottomAnchor,
leading: contentView.leadingAnchor,
bottom: textViewBottomAnchor,
trailing: contentView.trailingAnchor,
padding: .init(top: 4, left: 10, bottom: 0, right: 10))
guard let imageURL = self.post?.messageImageURL else {return} // if no image exists, return, preventing image view from taking extra memory and performance to initialize and calculate constraints
// initialize here instead of globally, so it doesnt take extra memory holding this when no image exists.
let messageImageView: UIImageView = {
let imageView = UIImageView()
imageView.kf.setImage(with: imageURL, placeholder: UIImage(systemName: "person.crop.circle.fill")!.withTintColor(.gray).withRenderingMode(.alwaysOriginal))
imageView.contentMode = .scaleAspectFit
imageView.layer.masksToBounds = true
imageView.layer.borderWidth = 1
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
addSubview(messageImageView)
messageImageView.anchor(top: messageTextView.bottomAnchor,
leading: contentView.leadingAnchor,
bottom: contentView.bottomAnchor,
trailing: contentView.trailingAnchor,
padding: .init(top: 4, left: 10, bottom: 0, right: 10))
}
Constraint error: 2021-05-11 13:18:28.184077-0700 GroupUp[8223:1981252] [LayoutConstraints] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. "<NSLayoutConstraint:0x283552170 V:[UILabel:0x10598a4e0]-(4)-[UIImageView:0x10881ca00] (active)>", "<NSLayoutConstraint:0x283550af0 UIImageView:0x10881ca00.bottom == UIView:0x10598a750.bottom (active)>", "<NSLayoutConstraint:0x28356db80 UILabel:0x10598a4e0.bottom == UIView:0x10598a750.bottom (active)>" Will attempt to recover by breaking constraint <NSLayoutConstraint:0x283552170 V:[UILabel:0x10598a4e0]-(4)-[UIImageView:0x10881ca00] (active)> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.