Make StatusContentContainer play nice with hiding subviews

This commit is contained in:
Shadowfacts 2022-10-04 22:48:42 -04:00
parent 7085ac01cb
commit 2196663d94
1 changed files with 52 additions and 16 deletions

View File

@ -30,48 +30,84 @@ class StatusContentContainer: UIView {
let pollView = StatusPollView() let pollView = StatusPollView()
private var lastSubviewBottomConstraint: NSLayoutConstraint! 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 zeroHeightConstraint: NSLayoutConstraint!
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
let subviews = [contentTextView, cardView, attachmentsView, pollView] for subview in arrangedSubviews {
for (index, subview) in subviews.enumerated() {
subview.translatesAutoresizingMaskIntoConstraints = false subview.translatesAutoresizingMaskIntoConstraints = false
addSubview(subview) addSubview(subview)
let topConstraint: NSLayoutConstraint
if index == 0 {
topConstraint = subview.topAnchor.constraint(equalTo: topAnchor)
} else {
topConstraint = subview.topAnchor.constraint(equalTo: subviews[index - 1].bottomAnchor, constant: 4)
}
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
topConstraint,
subview.leadingAnchor.constraint(equalTo: leadingAnchor), subview.leadingAnchor.constraint(equalTo: leadingAnchor),
subview.trailingAnchor.constraint(equalTo: trailingAnchor), subview.trailingAnchor.constraint(equalTo: trailingAnchor),
]) ])
} }
// these constraints need to have low priority so that during the collapse/expand animation, the content container is the view that shrinks/expands // 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!.bottomAnchor.constraint(equalTo: bottomAnchor)
lastSubviewBottomConstraint.isActive = true
lastSubviewBottomConstraint.priority = .defaultLow
zeroHeightConstraint = heightAnchor.constraint(equalToConstant: 0) zeroHeightConstraint = heightAnchor.constraint(equalToConstant: 0)
zeroHeightConstraint.priority = .defaultLow zeroHeightConstraint.priority = .defaultLow
setNeedsUpdateConstraints()
// mask to bounds so that the during the expand/collapse animation, subviews are clipped // mask to bounds so that the during the expand/collapse animation, subviews are clipped
layer.masksToBounds = true layer.masksToBounds = true
isHiddenObservations = arrangedSubviews.map {
$0.observe(\.isHidden) { [unowned self] _, _ in
self.setNeedsUpdateConstraints()
}
}
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") 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 = true
lastSubviewBottomConstraint!.priority = .defaultLow
super.updateConstraints()
}
func setCollapsed(_ collapsed: Bool) { func setCollapsed(_ collapsed: Bool) {
lastSubviewBottomConstraint.isActive = !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 zeroHeightConstraint.isActive = collapsed
} }