// // StatusContentContainer.swift // Tusker // // Created by Shadowfacts on 10/2/22. // Copyright © 2022 Shadowfacts. All rights reserved. // import UIKit class StatusContentContainer: UIView { let contentTextView = StatusContentTextView().configure { $0.adjustsFontForContentSizeCategory = true $0.isScrollEnabled = false $0.backgroundColor = nil $0.isEditable = false $0.isSelectable = false } let cardView = StatusCardView().configure { NSLayoutConstraint.activate([ $0.heightAnchor.constraint(equalToConstant: 65), ]) } let attachmentsView = AttachmentsContainerView().configure { NSLayoutConstraint.activate([ $0.heightAnchor.constraint(equalTo: $0.widthAnchor, multiplier: 9/16), ]) } let pollView = StatusPollView() private var arrangedSubviews: [UIView] { [contentTextView, cardView, attachmentsView, pollView] } private var isHiddenObservations: [NSKeyValueObservation] = [] private var verticalConstraints: [NSLayoutConstraint] = [] private var lastSubviewBottomConstraint: NSLayoutConstraint? private var zeroHeightConstraint: NSLayoutConstraint! private var isCollapsed = false override init(frame: CGRect) { super.init(frame: frame) for subview in arrangedSubviews { subview.translatesAutoresizingMaskIntoConstraints = false addSubview(subview) NSLayoutConstraint.activate([ subview.leadingAnchor.constraint(equalTo: leadingAnchor), subview.trailingAnchor.constraint(equalTo: trailingAnchor), ]) } // this constraint needs to have low priority so that during the collapse/expand animation, the content container is the view that shrinks/expands zeroHeightConstraint = heightAnchor.constraint(equalToConstant: 0) zeroHeightConstraint.priority = .defaultLow setNeedsUpdateConstraints() isHiddenObservations = arrangedSubviews.map { $0.observe(\.isHidden) { [unowned self] _, _ in self.setNeedsUpdateConstraints() } } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func updateConstraints() { NSLayoutConstraint.deactivate(verticalConstraints) verticalConstraints = [] var lastVisibleSubview: UIView? for subview in arrangedSubviews { guard !subview.isHidden else { continue } if let lastVisibleSubview { verticalConstraints.append(subview.topAnchor.constraint(equalTo: lastVisibleSubview.bottomAnchor, constant: 4)) } else { verticalConstraints.append(subview.topAnchor.constraint(equalTo: topAnchor)) } lastVisibleSubview = subview } NSLayoutConstraint.activate(verticalConstraints) lastSubviewBottomConstraint?.isActive = false // this constraint needs to have low priority so that during the collapse/expand animation, the content container is the view that shrinks/expands lastSubviewBottomConstraint = subviews.last(where: { !$0.isHidden })!.bottomAnchor.constraint(equalTo: bottomAnchor) lastSubviewBottomConstraint!.isActive = !isCollapsed lastSubviewBottomConstraint!.priority = .defaultLow zeroHeightConstraint.isActive = isCollapsed super.updateConstraints() } func setCollapsed(_ collapsed: Bool) { guard collapsed != isCollapsed else { return } isCollapsed = collapsed // ensure that we have a lastSubviewBottomConstraint updateConstraintsIfNeeded() // force unwrap because the content container should always have at least one view lastSubviewBottomConstraint!.isActive = !collapsed zeroHeightConstraint.isActive = collapsed } }