// // StackView.swift // App // // Created by James Magahern on 9/22/20. // import UIKit class StackView: UIView { var arrangedSubviews: [UIView] = [] { didSet { setNeedsLayout() } } var layoutDimension: UIAxis = .vertical convenience init(dimension: UIAxis) { self.init(frame: .zero) self.layoutDimension = dimension } // Convenience public func addArrangedSubview(_ view: UIView) { addSubview(view) arrangedSubviews.append(view) setNeedsLayout() } public func removeArrangedSubview(_ view: UIView) { if view.superview == self { view.removeFromSuperview() } arrangedSubviews.removeAll { $0 == view } setNeedsLayout() } public func removeAllArrangedSubviews() { arrangedSubviews.forEach { $0.removeFromSuperview() } arrangedSubviews.removeAll() setNeedsLayout() } override func sizeThatFits(_ containerSize: CGSize) -> CGSize { var size: CGSize = .zero if layoutDimension == .horizontal { size.height = containerSize.height } else { size.width = containerSize.width } var spaceRemaining = containerSize for view in arrangedSubviews { let viewSize = view.sizeThatFits(spaceRemaining) if layoutDimension == .horizontal { size.width += viewSize.width spaceRemaining.width -= viewSize.width } else { size.height += viewSize.height spaceRemaining.height -= viewSize.height } } return size } override func layoutSubviews() { super.layoutSubviews() var origin: CGPoint = CGPoint(x: safeAreaInsets.left, y: safeAreaInsets.top) var spaceRemaining = bounds.size for view in arrangedSubviews { var viewSize = view.sizeThatFits(spaceRemaining) var offset: CGPoint = .zero if layoutDimension == .horizontal { offset.x = viewSize.width viewSize.height = bounds.height spaceRemaining.width -= viewSize.width } else { offset.y = viewSize.height viewSize.width = bounds.width spaceRemaining.height -= viewSize.height } view.frame = CGRect(origin: origin, size: viewSize) origin.x += offset.x origin.y += offset.y } } }