119 lines
5.1 KiB
Swift
119 lines
5.1 KiB
Swift
//
|
|
// RadioButton.swift
|
|
// VDS
|
|
//
|
|
// Created by Matt Bruce on 6/5/23.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import Combine
|
|
import VDSCoreTokens
|
|
|
|
/// Radio buttons are single-select components through which a customer indicates a choice.
|
|
/// They must always be paired with one or more ``RadioButtonItem`` within a ``RadioButtonGroup``.
|
|
/// Use radio buttons to display choices like delivery method.
|
|
@objc(VDSRadioButton)
|
|
open class RadioButton: SelectorBase {
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Initializers
|
|
//--------------------------------------------------
|
|
required public init() {
|
|
super.init(frame: .zero)
|
|
}
|
|
|
|
public override init(frame: CGRect) {
|
|
super.init(frame: .zero)
|
|
}
|
|
|
|
public required init?(coder: NSCoder) {
|
|
super.init(coder: coder)
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Private Properties
|
|
//--------------------------------------------------
|
|
private var selectorSize = CGSize(width: 10, height: 10)
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Overrides
|
|
//--------------------------------------------------
|
|
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
|
open override func setup() {
|
|
super.setup()
|
|
|
|
backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error)
|
|
backgroundColorConfiguration.setSurfaceColors(.clear, .clear, forState: [.error, .disabled])
|
|
|
|
borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected)
|
|
borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .highlighted)
|
|
borderColorConfiguration.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal)
|
|
borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled)
|
|
borderColorConfiguration.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error)
|
|
|
|
borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled])
|
|
borderColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.error, .disabled])
|
|
|
|
selectorColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected)
|
|
selectorColorConfiguration.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled])
|
|
|
|
}
|
|
|
|
/// This will change the state of the Selector and execute the actionBlock if provided.
|
|
open override func toggle() {
|
|
guard !isSelected, isEnabled else { return }
|
|
|
|
//removed error
|
|
if showError && isSelected == false {
|
|
showError.toggle()
|
|
}
|
|
isSelected.toggle()
|
|
sendActions(for: .valueChanged)
|
|
}
|
|
|
|
open override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
|
|
//get the colors
|
|
let backgroundColor = backgroundColorConfiguration.getColor(self)
|
|
let borderColor = borderColorConfiguration.getColor(self)
|
|
let selectorColor = selectorColorConfiguration.getColor(self)
|
|
|
|
if let shapeLayer = shapeLayer, let sublayers = layer.sublayers, sublayers.contains(shapeLayer) {
|
|
shapeLayer.removeFromSuperlayer()
|
|
self.shapeLayer = nil
|
|
}
|
|
|
|
let bounds = bounds
|
|
|
|
self.backgroundColor = backgroundColor
|
|
layer.borderColor = borderColor.cgColor
|
|
layer.cornerRadius = bounds.width * 0.5
|
|
layer.borderWidth = VDSFormControls.borderWidth
|
|
|
|
if shapeLayer == nil {
|
|
let selectedBounds = selectorSize
|
|
let bezierPath = UIBezierPath(ovalIn: CGRect(x: (bounds.width - selectedBounds.width) / 2,
|
|
y: (bounds.height - selectedBounds.height) / 2,
|
|
width: selectorSize.width,
|
|
height: selectorSize.height))
|
|
let shapeLayer = CAShapeLayer()
|
|
self.shapeLayer = shapeLayer
|
|
shapeLayer.frame = bounds
|
|
layer.addSublayer(shapeLayer)
|
|
shapeLayer.fillColor = selectorColor.cgColor
|
|
shapeLayer.path = bezierPath.cgPath
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: AppleGuidelinesTouchable
|
|
extension RadioButton: AppleGuidelinesTouchable {
|
|
/// Overrides to ensure that the touch point meets a minimum of the minimumTappableArea.
|
|
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
|
Self.acceptablyOutsideBounds(point: point, bounds: bounds)
|
|
}
|
|
|
|
}
|