Adds back/forward buttons to page menu

This commit is contained in:
James Magahern
2021-02-11 12:26:13 -08:00
parent bd400a006d
commit f32c90f2e3
7 changed files with 127 additions and 12 deletions

View 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)
)
}
}
}