Adds back/forward buttons to page menu
This commit is contained in:
139
App/Common UI/StackView.swift
Normal file
139
App/Common UI/StackView.swift
Normal file
@@ -0,0 +1,139 @@
|
||||
//
|
||||
// StackView.swift
|
||||
// App
|
||||
//
|
||||
// Created by James Magahern on 9/22/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class StackView<T: UIView>: UIView
|
||||
{
|
||||
public enum LayoutType {
|
||||
case intrinsicSize
|
||||
case equalSize
|
||||
}
|
||||
|
||||
var arrangedSubviews: [T] = []
|
||||
{ didSet { setNeedsLayout() } }
|
||||
|
||||
var layoutDimension: UIAxis = .vertical
|
||||
var layoutType: LayoutType = .intrinsicSize
|
||||
|
||||
convenience init(dimension: UIAxis = .vertical, layoutType: LayoutType = .intrinsicSize) {
|
||||
self.init(frame: .zero)
|
||||
self.layoutDimension = dimension
|
||||
self.layoutType = layoutType
|
||||
}
|
||||
|
||||
// Convenience
|
||||
public func addArrangedSubview(_ view: T) {
|
||||
addSubview(view)
|
||||
arrangedSubviews.append(view)
|
||||
setNeedsLayout()
|
||||
}
|
||||
|
||||
public func removeArrangedSubview(_ view: T) {
|
||||
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()
|
||||
|
||||
if layoutType == .intrinsicSize {
|
||||
layoutWithIntrinsicSize()
|
||||
} else if layoutType == .equalSize {
|
||||
layoutWithEqualSize()
|
||||
} else {
|
||||
fatalError("StackView: I don't know how to lay out this type")
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func layoutWithIntrinsicSize() {
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fileprivate func layoutWithEqualSize() {
|
||||
let numberOfItems = arrangedSubviews.count
|
||||
|
||||
let structureDimension: CGFloat = (
|
||||
(layoutDimension == .horizontal) ? bounds.height : bounds.width
|
||||
)
|
||||
|
||||
let itemDimension: CGFloat = (
|
||||
(layoutDimension == .horizontal) ? (bounds.width / CGFloat(numberOfItems)) : (bounds.height / CGFloat(numberOfItems))
|
||||
)
|
||||
|
||||
var origin: CGPoint = CGPoint(x: safeAreaInsets.left, y: safeAreaInsets.top)
|
||||
for view in arrangedSubviews {
|
||||
let size: CGSize = (
|
||||
(layoutDimension == .horizontal)
|
||||
? CGSize(width: itemDimension, height: structureDimension)
|
||||
: CGSize(width: structureDimension, height: itemDimension)
|
||||
)
|
||||
|
||||
view.frame = CGRect(origin: origin, size: size)
|
||||
|
||||
origin = (
|
||||
(layoutDimension == .horizontal)
|
||||
? CGPoint(x: origin.x + size.width, y: origin.y)
|
||||
: CGPoint(x: origin.x, y: origin.y + size.height)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user