SegmentedReliefButton: actually show background states
This commit is contained in:
@@ -13,18 +13,29 @@ class ReliefButton: UIButton
|
||||
internal let backgroundView = GradientView(direction: .vertical, colors: ReliefButton.gradientColors(inverted: false, darkMode: false))
|
||||
|
||||
static let padding = CGFloat(24.0)
|
||||
static let cornerRadius = CGFloat(4.0)
|
||||
static let borderWidth = CGFloat(1.0)
|
||||
|
||||
override var isHighlighted: Bool {
|
||||
didSet {
|
||||
get {
|
||||
super.isHighlighted || remainsPressed
|
||||
}
|
||||
|
||||
set {
|
||||
super.isHighlighted = newValue
|
||||
setBackgroundInverted(isHighlighted)
|
||||
}
|
||||
}
|
||||
|
||||
var remainsPressed: Bool = false {
|
||||
didSet {
|
||||
self.isHighlighted = remainsPressed
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
super.init(frame: .zero)
|
||||
|
||||
let cornerRadius = CGFloat(4.0)
|
||||
|
||||
self.tintColor = .init(dynamicProvider: { traitCollection -> UIColor in
|
||||
if traitCollection.userInterfaceStyle == .light {
|
||||
return .init(white: 0.15, alpha: 1.0)
|
||||
@@ -40,16 +51,16 @@ class ReliefButton: UIButton
|
||||
shadowView.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
|
||||
shadowView.layer.shadowRadius = 1.0
|
||||
shadowView.layer.shadowOpacity = 1.0
|
||||
shadowView.layer.cornerRadius = cornerRadius
|
||||
shadowView.layer.cornerRadius = Self.cornerRadius
|
||||
shadowView.layer.masksToBounds = false
|
||||
shadowView.layer.shouldRasterize = true
|
||||
shadowView.layer.rasterizationScale = UIScreen.main.scale
|
||||
addSubview(shadowView)
|
||||
|
||||
backgroundView.layer.cornerRadius = cornerRadius
|
||||
backgroundView.layer.cornerRadius = Self.cornerRadius
|
||||
backgroundView.isUserInteractionEnabled = false
|
||||
backgroundView.layer.masksToBounds = true
|
||||
backgroundView.layer.borderWidth = 1.0
|
||||
backgroundView.layer.borderWidth = Self.borderWidth
|
||||
addSubview(backgroundView)
|
||||
|
||||
traitCollectionDidChange(nil)
|
||||
@@ -131,5 +142,9 @@ class ReliefButton: UIButton
|
||||
backgroundView.frame = CGRect(origin: .zero, size: CGSize(width: backgroundDimension, height: backgroundDimension))
|
||||
backgroundView.frame = backgroundView.frame.centeredX(inRect: bounds)
|
||||
shadowView.frame = backgroundView.frame
|
||||
|
||||
// Offset by a small amount. Visual illusion caused by the shadow
|
||||
backgroundView.frame = backgroundView.frame.offsetBy(dx: 0.0, dy: 1.0)
|
||||
shadowView.frame = shadowView.frame.offsetBy(dx: 0.0, dy: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,22 @@ class SegmentedReliefButton: ReliefButton
|
||||
didSet { children.forEach { addSubview($0) }; setNeedsLayout() }
|
||||
}
|
||||
|
||||
private let backgroundMaskView = UIView(frame: .zero)
|
||||
private let backgroundsContainerView = UIView(frame: .zero)
|
||||
private var childrenHighlighObservations: [NSKeyValueObservation] = []
|
||||
|
||||
init(children: [ReliefButton]) {
|
||||
super.init()
|
||||
self.children = children
|
||||
|
||||
backgroundMaskView.backgroundColor = .black
|
||||
backgroundMaskView.layer.masksToBounds = true
|
||||
backgroundMaskView.layer.cornerRadius = Self.cornerRadius - Self.borderWidth
|
||||
|
||||
backgroundsContainerView.clipsToBounds = true
|
||||
backgroundsContainerView.mask = backgroundMaskView
|
||||
|
||||
addSubview(backgroundsContainerView)
|
||||
}
|
||||
|
||||
override var isHighlighted: Bool {
|
||||
@@ -28,23 +41,36 @@ class SegmentedReliefButton: ReliefButton
|
||||
}
|
||||
|
||||
override func sizeThatFits(_ size: CGSize) -> CGSize {
|
||||
let ourSize = super.sizeThatFits(size)
|
||||
let width: CGFloat = children.reduce(0.0) { (result, button) -> CGFloat in
|
||||
return result + button.sizeThatFits(size).width
|
||||
}
|
||||
|
||||
return CGSize(width: width, height: size.height)
|
||||
return CGSize(width: width, height: ourSize.height)
|
||||
}
|
||||
|
||||
override func setBackgroundInverted(_ inverted: Bool) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
backgroundView.colors = [ .clear ]
|
||||
backgroundView.frame = bounds
|
||||
shadowView.frame = bounds
|
||||
|
||||
backgroundMaskView.frame = backgroundView.frame.insetBy(dx: 1.0, dy: 1.0)
|
||||
backgroundsContainerView.frame = backgroundView.frame
|
||||
|
||||
childrenHighlighObservations.removeAll()
|
||||
backgroundsContainerView.subviews.forEach { $0.removeFromSuperview() }
|
||||
|
||||
let darkMode = self.traitCollection.userInterfaceStyle == .dark
|
||||
var buttonRect = CGRect(origin: .zero, size: CGSize(width: 0, height: bounds.height))
|
||||
for child in children {
|
||||
for (i, child) in children.enumerated() {
|
||||
child.shadowView.isHidden = true
|
||||
child.backgroundView.layer.borderWidth = 0
|
||||
child.backgroundView.isHidden = true
|
||||
bringSubviewToFront(child)
|
||||
|
||||
let childSize = child.sizeThatFits(bounds.size)
|
||||
@@ -52,6 +78,26 @@ class SegmentedReliefButton: ReliefButton
|
||||
child.frame = buttonRect
|
||||
|
||||
buttonRect.origin.x += buttonRect.width
|
||||
|
||||
// Background
|
||||
let backgroundView = GradientView(direction: .vertical, colors: Self.gradientColors(inverted: false, darkMode: darkMode))
|
||||
backgroundView.frame = child.frame
|
||||
backgroundsContainerView.insertSubview(backgroundView, at: 0)
|
||||
childrenHighlighObservations.append(child.observe(\.isHighlighted) { [backgroundView] (button, changeEvent) in
|
||||
backgroundView.colors = Self.gradientColors(inverted: button.isHighlighted, darkMode: darkMode)
|
||||
})
|
||||
|
||||
// Separator
|
||||
if i < children.count - 1 {
|
||||
let separatorView = UIView(frame: CGRect(
|
||||
x: child.frame.maxX,
|
||||
y: 0,
|
||||
width: 1.0,
|
||||
height: bounds.height
|
||||
))
|
||||
separatorView.backgroundColor = .systemFill
|
||||
backgroundsContainerView.addSubview(separatorView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,19 +28,19 @@ class ScriptPolicyControl: UIControl
|
||||
segmentContainer.children = [ allowButton, denyButton ]
|
||||
addSubview(segmentContainer)
|
||||
|
||||
allowButton.showsTouchWhenHighlighted = false
|
||||
allowButton.addAction(UIAction(handler: { [unowned self] _ in
|
||||
self.policyStatus = .allowed
|
||||
self.sendActions(for: .valueChanged)
|
||||
}), for: .touchUpInside)
|
||||
allowButton.imageView?.contentMode = .scaleAspectFit
|
||||
addSubview(allowButton)
|
||||
|
||||
denyButton.showsTouchWhenHighlighted = false
|
||||
denyButton.addAction(UIAction(handler: { [unowned self] _ in
|
||||
self.policyStatus = .blocked
|
||||
self.sendActions(for: .valueChanged)
|
||||
}), for: .touchUpInside)
|
||||
denyButton.imageView?.contentMode = .scaleAspectFit
|
||||
addSubview(denyButton)
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
@@ -54,15 +54,19 @@ class ScriptPolicyControl: UIControl
|
||||
|
||||
if policyStatus == .allowed {
|
||||
allowButton.tintColor = .blue
|
||||
allowButton.remainsPressed = true
|
||||
allowButton.setImage(UIImage(systemName: "play.circle.fill"), for: .normal)
|
||||
|
||||
denyButton.tintColor = .darkGray
|
||||
denyButton.tintColor = nil
|
||||
denyButton.remainsPressed = false
|
||||
denyButton.setImage(UIImage(systemName: "stop.circle"), for: .normal)
|
||||
} else {
|
||||
allowButton.tintColor = .darkGray
|
||||
allowButton.tintColor = nil
|
||||
allowButton.remainsPressed = false
|
||||
allowButton.setImage(UIImage(systemName: "play.circle"), for: .normal)
|
||||
|
||||
denyButton.tintColor = .red
|
||||
denyButton.remainsPressed = true
|
||||
denyButton.setImage(UIImage(systemName: "stop.circle.fill"), for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user