2020-08-14 15:55:08 -07:00
|
|
|
//
|
|
|
|
|
// ReliefButton.swift
|
|
|
|
|
// App
|
|
|
|
|
//
|
|
|
|
|
// Created by James Magahern on 8/14/20.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
|
|
|
|
|
|
class ReliefButton: UIButton
|
|
|
|
|
{
|
2020-09-30 18:06:47 -07:00
|
|
|
public var constrainedToSquare = true
|
|
|
|
|
|
2021-07-20 19:17:04 -07:00
|
|
|
internal var cornerRadius = CGFloat(6.0) { didSet { setNeedsLayout() } }
|
2020-08-14 15:55:08 -07:00
|
|
|
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)
|
2021-06-14 16:32:51 -07:00
|
|
|
static let borderWidth = CGFloat(1.0 / UIScreen.main.scale)
|
2020-08-14 15:55:08 -07:00
|
|
|
|
|
|
|
|
override var isHighlighted: Bool {
|
2020-08-14 18:42:40 -07:00
|
|
|
get {
|
|
|
|
|
super.isHighlighted || remainsPressed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set {
|
|
|
|
|
super.isHighlighted = newValue
|
2020-08-14 15:55:08 -07:00
|
|
|
setBackgroundInverted(isHighlighted)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-14 18:42:40 -07:00
|
|
|
var remainsPressed: Bool = false {
|
|
|
|
|
didSet {
|
|
|
|
|
self.isHighlighted = remainsPressed
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-14 15:55:08 -07:00
|
|
|
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
|
2020-09-22 14:33:00 -07:00
|
|
|
shadowView.layer.cornerCurve = .continuous
|
2020-08-14 15:55:08 -07:00
|
|
|
addSubview(shadowView)
|
|
|
|
|
|
|
|
|
|
backgroundView.isUserInteractionEnabled = false
|
|
|
|
|
backgroundView.layer.masksToBounds = true
|
2020-08-14 18:42:40 -07:00
|
|
|
backgroundView.layer.borderWidth = Self.borderWidth
|
2020-09-22 14:33:00 -07:00
|
|
|
backgroundView.layer.cornerCurve = .continuous
|
2020-09-30 18:26:45 -07:00
|
|
|
backgroundView.layer.shouldRasterize = true
|
|
|
|
|
backgroundView.layer.rasterizationScale = UIScreen.main.scale
|
2020-08-14 15:55:08 -07:00
|
|
|
addSubview(backgroundView)
|
|
|
|
|
|
|
|
|
|
traitCollectionDidChange(nil)
|
2021-04-19 17:55:24 -07:00
|
|
|
|
|
|
|
|
pointerStyleProvider = { (button, pointerEffect, pointerShape) -> UIPointerStyle? in
|
|
|
|
|
let preview = UITargetedPreview(view: button)
|
|
|
|
|
return UIPointerStyle(effect: .lift(preview), shape: pointerShape)
|
|
|
|
|
}
|
2020-08-14 15:55:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
required init?(coder: NSCoder) {
|
|
|
|
|
fatalError("init(coder:) has not been implemented")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static func gradientColors(inverted: Bool, darkMode: Bool) -> [UIColor] {
|
2022-02-21 15:52:18 -08:00
|
|
|
let colors = { darkMode -> [UIColor] in
|
|
|
|
|
if darkMode {
|
2020-08-14 15:55:08 -07:00
|
|
|
return [
|
2022-02-21 15:52:18 -08:00
|
|
|
UIColor(white: 0.15, alpha: 1.0),
|
|
|
|
|
UIColor(white: 0.08, alpha: 1.0)
|
2020-08-14 15:55:08 -07:00
|
|
|
]
|
|
|
|
|
} else {
|
|
|
|
|
return [
|
|
|
|
|
UIColor(white: 0.98, alpha: 1.0),
|
|
|
|
|
UIColor(white: 0.93, alpha: 1.0)
|
|
|
|
|
]
|
|
|
|
|
}
|
2022-02-21 15:52:18 -08:00
|
|
|
} (darkMode)
|
|
|
|
|
|
|
|
|
|
return inverted ? colors.reversed() : colors
|
2020-08-14 15:55:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
|
|
|
setBackgroundInverted(isHighlighted)
|
|
|
|
|
backgroundView.layer.borderColor = { traitCollection -> UIColor in
|
|
|
|
|
if traitCollection.userInterfaceStyle == .dark {
|
2022-02-21 15:52:18 -08:00
|
|
|
return .init(white: 0.30, alpha: 1.0)
|
2020-08-14 15:55:08 -07:00
|
|
|
} 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 {
|
2020-08-14 17:40:01 -07:00
|
|
|
let ratio = CGFloat(0.45)
|
2021-10-21 15:08:04 -07:00
|
|
|
let constantSize = round(ratio * contentRect.width)
|
2020-08-14 17:40:01 -07:00
|
|
|
return CGRect(
|
|
|
|
|
origin: .zero,
|
|
|
|
|
size: CGSize(
|
2021-10-21 15:08:04 -07:00
|
|
|
// Ensure multiple of two for proper centering.
|
|
|
|
|
width: constantSize + constantSize.truncatingRemainder(dividingBy: 2),
|
|
|
|
|
height: constantSize + constantSize.truncatingRemainder(dividingBy: 2)
|
2020-08-14 17:40:01 -07:00
|
|
|
)
|
|
|
|
|
).centered(inRect: contentRect)
|
2020-08-14 15:55:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
2020-09-30 18:06:47 -07:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-14 15:55:08 -07:00
|
|
|
shadowView.frame = backgroundView.frame
|
2020-09-30 18:26:45 -07:00
|
|
|
|
2021-06-14 16:32:51 -07:00
|
|
|
let shadowPath = UIBezierPath(roundedRect: shadowView.bounds, cornerRadius: cornerRadius)
|
2020-09-30 18:26:45 -07:00
|
|
|
shadowView.layer.shadowPath = shadowPath.cgPath
|
2021-06-14 16:32:51 -07:00
|
|
|
|
|
|
|
|
backgroundView.layer.cornerRadius = cornerRadius
|
|
|
|
|
shadowView.layer.cornerRadius = cornerRadius
|
2020-08-14 15:55:08 -07:00
|
|
|
}
|
|
|
|
|
}
|