class SimpleStackView: UIView { var padding:CGFloat = 0 { didSet { setNeedsLayout() } } var spacing:CGFloat = 0 { didSet { setNeedsLayout() } } var arrangedSubViews:[UIView]? { willSet { guard let arrangedSubViews = arrangedSubViews else { return } for arrangedSubView in arrangedSubViews { if arrangedSubView.isDescendant(of: self) { arrangedSubView.removeFromSuperview() } } } didSet { guard let arrangedSubViews = arrangedSubViews else { return } for arrangedSubView in arrangedSubViews { addSubview(arrangedSubView) } setNeedsLayout() } } override func sizeThatFits(_ size: CGSize) -> CGSize { guard let arrangedSubViews = arrangedSubViews, arrangedSubViews.count > 0 else { return CGSize.zero } var heightThatFits:CGFloat = 0 let contentSize = CGSize.init(width: size.width-2*padding, height: size.height-2*padding) for arrangedSubView in arrangedSubViews { heightThatFits += arrangedSubView.sizeThatFits(contentSize).height } heightThatFits += CGFloat(arrangedSubViews.count - 1) * spacing return CGSize.init(width: size.width, height: heightThatFits + 2*padding) } override func layoutSubviews() { super.layoutSubviews() guard let arrangedSubViews = arrangedSubViews else { return } let size = self.bounds.size let contentSize = CGSize.init(width: size.width-2*padding, height: size.height-2*padding) var top = padding for arrangedSubView in arrangedSubViews { let height = arrangedSubView.sizeThatFits(contentSize).height arrangedSubView.frame = CGRect.init(x: padding, y: top, width: contentSize.width, height: height) top = arrangedSubView.frame.maxY + spacing } } }