Files
Attractor/App/Common UI/ReliefButton.swift
2021-06-14 16:37:03 -07:00

167 lines
5.6 KiB
Swift

//
// ReliefButton.swift
// App
//
// Created by James Magahern on 8/14/20.
//
import UIKit
class ReliefButton: UIButton
{
public var constrainedToSquare = true
internal var cornerRadius = CGFloat(8.0) { didSet { setNeedsLayout() } }
internal let shadowView = UIView(frame: .zero)
internal let backgroundView = GradientView(direction: .vertical, colors: ReliefButton.gradientColors(inverted: false, darkMode: false))
static let padding = CGFloat(24.0)
static let borderWidth = CGFloat(1.0 / UIScreen.main.scale)
override var isHighlighted: Bool {
get {
super.isHighlighted || remainsPressed
}
set {
super.isHighlighted = newValue
setBackgroundInverted(isHighlighted)
}
}
var remainsPressed: Bool = false {
didSet {
self.isHighlighted = remainsPressed
}
}
init() {
super.init(frame: .zero)
self.tintColor = .init(dynamicProvider: { traitCollection -> UIColor in
if traitCollection.userInterfaceStyle == .light {
return .init(white: 0.15, alpha: 1.0)
} else {
return .white
}
})
shadowView.alpha = 0.28
shadowView.backgroundColor = UIColor(white: 0.0, alpha: 1.0)
shadowView.isUserInteractionEnabled = false
shadowView.layer.shadowColor = UIColor.black.cgColor
shadowView.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
shadowView.layer.shadowRadius = 1.0
shadowView.layer.shadowOpacity = 1.0
shadowView.layer.masksToBounds = false
shadowView.layer.shouldRasterize = true
shadowView.layer.rasterizationScale = UIScreen.main.scale
shadowView.layer.cornerCurve = .continuous
addSubview(shadowView)
backgroundView.isUserInteractionEnabled = false
backgroundView.layer.masksToBounds = true
backgroundView.layer.borderWidth = Self.borderWidth
backgroundView.layer.cornerCurve = .continuous
backgroundView.layer.shouldRasterize = true
backgroundView.layer.rasterizationScale = UIScreen.main.scale
addSubview(backgroundView)
traitCollectionDidChange(nil)
pointerStyleProvider = { (button, pointerEffect, pointerShape) -> UIPointerStyle? in
let preview = UITargetedPreview(view: button)
return UIPointerStyle(effect: .lift(preview), shape: pointerShape)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
static func gradientColors(inverted: Bool, darkMode: Bool) -> [UIColor] {
if darkMode {
if !inverted {
return [
UIColor(white: 0.20, alpha: 1.0),
UIColor(white: 0.10, alpha: 1.0)
]
} else {
return [
UIColor(white: 0.10, alpha: 1.0),
UIColor(white: 0.30, alpha: 1.0)
]
}
} else {
if !inverted {
return [
UIColor(white: 0.98, alpha: 1.0),
UIColor(white: 0.93, alpha: 1.0)
]
} else {
return [
UIColor(white: 0.88, alpha: 1.0),
UIColor(white: 0.93, alpha: 1.0)
]
}
}
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
setBackgroundInverted(isHighlighted)
backgroundView.layer.borderColor = { traitCollection -> UIColor in
if traitCollection.userInterfaceStyle == .dark {
return .init(white: 0.34, alpha: 1.0)
} else {
return .white
}
}(traitCollection).cgColor
}
internal func setBackgroundInverted(_ inverted: Bool) {
let darkMode: Bool = (traitCollection.userInterfaceStyle == .dark)
backgroundView.colors = Self.gradientColors(inverted: inverted, darkMode: darkMode)
}
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
let ratio = CGFloat(0.45)
return CGRect(
origin: .zero,
size: CGSize(
width: ratio * contentRect.width,
height: ratio * contentRect.width
)
).centered(inRect: contentRect)
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
let ourSize = super.sizeThatFits(size)
return CGSize(width: ourSize.width + Self.padding, height: ourSize.height)
}
override func layoutSubviews() {
self.imageView?.contentMode = .scaleAspectFit
super.layoutSubviews()
sendSubviewToBack(backgroundView)
sendSubviewToBack(shadowView)
if constrainedToSquare {
let backgroundDimension = bounds.height
backgroundView.frame = CGRect(origin: .zero, size: CGSize(width: backgroundDimension, height: backgroundDimension))
backgroundView.frame = backgroundView.frame.centeredX(inRect: bounds)
} else {
backgroundView.frame = bounds
}
shadowView.frame = backgroundView.frame
let shadowPath = UIBezierPath(roundedRect: shadowView.bounds, cornerRadius: cornerRadius)
shadowView.layer.shadowPath = shadowPath.cgPath
backgroundView.layer.cornerRadius = cornerRadius
shadowView.layer.cornerRadius = cornerRadius
}
}