updated toggle
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
74cbd6a2fe
commit
6c0a0460e8
@ -8,6 +8,7 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
import Combine
|
||||
/**
|
||||
A custom implementation of Apple's UISwitch.
|
||||
|
||||
@ -16,60 +17,53 @@ import VDSColorTokens
|
||||
Container: The background of the toggle control.
|
||||
Knob: The circular indicator that slides on the container.
|
||||
*/
|
||||
@objcMembers open class VDSToggle: Control<VDSToggleModel>, Changable {
|
||||
|
||||
|
||||
public class DefaultToggleModel: DefaultLabelModel, VDSToggleModel, ObservableObject {
|
||||
public var id: String?
|
||||
public var inputId: String?
|
||||
public var disabled: Bool = false
|
||||
public var showText: Bool = false
|
||||
public var on: Bool = false
|
||||
public var offText: String = "Off"
|
||||
public var onText: String = "On"
|
||||
public var value: AnyHashable? = true
|
||||
public var dataAnalyticsTrack: String?
|
||||
public var dataClickStream: String?
|
||||
public var dataTrack: String?
|
||||
public var accessibilityHintEnabled: String?
|
||||
public var accessibilityHintDisabled: String?
|
||||
public var accessibilityValueEnabled: String?
|
||||
public var accessibilityValueDisabled: String?
|
||||
public var accessibilityLabelEnabled: String?
|
||||
public var accessibilityLabelDisabled: String?
|
||||
|
||||
public required init() {
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
@objcMembers open class VDSToggle: VDSControl, Modelable, Changable {
|
||||
|
||||
public typealias ModelType = VDSToggleModel
|
||||
@Published public var model: ModelType = DefaultToggleModel()
|
||||
private var cancellable: AnyCancellable?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
/// Holds the on and off colors for the container.
|
||||
public var containerTintColor: (on: UIColor, off: UIColor) = (on: VDSColor.paletteGreen26, off: VDSColor.paletteGray44)
|
||||
private var containerTintColor: (on: UIColor, off: UIColor) = (on: VDSColor.paletteGreen26, off: VDSColor.paletteGray44)
|
||||
|
||||
/// Holds the on and off colors for the knob.
|
||||
public var knobTintColor: (on: UIColor, off: UIColor) = (on: VDSColor.paletteWhite, off: VDSColor.paletteWhite)
|
||||
private var knobTintColor: (on: UIColor, off: UIColor) = (on: VDSColor.paletteWhite, off: VDSColor.paletteWhite)
|
||||
|
||||
/// Holds the on and off colors for the disabled state..
|
||||
public var disabledTintColor: (container: UIColor, knob: UIColor) = (container: VDSColor.paletteGray11, knob: VDSColor.paletteWhite)
|
||||
|
||||
/// Set this flag to false if you do not want to animate state changes.
|
||||
public var isAnimated = true
|
||||
|
||||
public var onChange: Blocks.ActionBlock?
|
||||
|
||||
private var showText: Bool {
|
||||
return model?.showText ?? false
|
||||
}
|
||||
|
||||
private var onText: String {
|
||||
return model?.onText ?? "On"
|
||||
}
|
||||
|
||||
private var offText: String {
|
||||
return model?.offText ?? "off"
|
||||
}
|
||||
|
||||
private var disabledTintColor: (container: UIColor, knob: UIColor) = (container: VDSColor.paletteGray11, knob: VDSColor.paletteWhite)
|
||||
|
||||
private var showTextSpacing: CGFloat {
|
||||
showText ? 12 : 0
|
||||
}
|
||||
|
||||
private var textPosition: VDSTextPosition {
|
||||
return model?.textPosition ?? .left
|
||||
}
|
||||
|
||||
private var fontSize: VDSFontSize {
|
||||
return model?.fontSize ?? .small
|
||||
}
|
||||
|
||||
private var fontWeight: VDSFontWeight {
|
||||
return model?.fontWeight ?? .regular
|
||||
}
|
||||
|
||||
// Sizes are from InVision design specs.
|
||||
public static var toggleSize = CGSize(width: 52, height: 24)
|
||||
open class func getToggleScaledSize() -> CGSize { return Self.toggleSize }
|
||||
|
||||
public static var knobSize = CGSize(width: 20, height: 20)
|
||||
open class func getKnobScaledSize() -> CGSize { return Self.knobSize }
|
||||
|
||||
private var stackView: UIStackView = {
|
||||
let stackView = UIStackView()
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
@ -78,8 +72,8 @@ import VDSColorTokens
|
||||
return stackView
|
||||
}()
|
||||
|
||||
private var label: UILabel = {
|
||||
let label = UILabel()
|
||||
private var label: VDSLabel = {
|
||||
let label = VDSLabel()
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
return label
|
||||
}()
|
||||
@ -97,16 +91,105 @@ import VDSColorTokens
|
||||
return view
|
||||
}()
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
/// Set this flag to false if you do not want to animate state changes.
|
||||
public var isAnimated = true
|
||||
|
||||
public var onChange: Blocks.ActionBlock?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Static Properties
|
||||
//--------------------------------------------------
|
||||
// Sizes are from InVision design specs.
|
||||
public static var toggleSize = CGSize(width: 52, height: 24)
|
||||
open class func getToggleScaledSize() -> CGSize { return Self.toggleSize }
|
||||
|
||||
public static var knobSize = CGSize(width: 20, height: 20)
|
||||
open class func getKnobScaledSize() -> CGSize { return Self.knobSize }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Computed Properties
|
||||
//--------------------------------------------------
|
||||
public var showText: Bool {
|
||||
get { model.showText }
|
||||
set {
|
||||
if model.showText != newValue {
|
||||
model.showText = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var onText: String {
|
||||
get { model.onText }
|
||||
set {
|
||||
if model.onText != newValue {
|
||||
model.onText = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var offText: String {
|
||||
get { model.offText }
|
||||
set {
|
||||
if model.offText != newValue {
|
||||
model.offText = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var textPosition: VDSTextPosition {
|
||||
get { model.textPosition }
|
||||
set {
|
||||
if model.textPosition != newValue {
|
||||
model.textPosition = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var fontSize: VDSFontSize {
|
||||
get { model.fontSize }
|
||||
set {
|
||||
if model.fontSize != newValue {
|
||||
model.fontSize = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var fontWeight: VDSFontWeight {
|
||||
get { model.fontWeight }
|
||||
set {
|
||||
if model.fontWeight != newValue {
|
||||
model.fontWeight = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var surface: Surface {
|
||||
get { model.surface }
|
||||
set {
|
||||
if model.surface != newValue {
|
||||
model.surface = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open override var isEnabled: Bool {
|
||||
didSet {
|
||||
isUserInteractionEnabled = isEnabled
|
||||
changeStateNoAnimation(isEnabled ? isOn : false)
|
||||
get { !model.disabled }
|
||||
set {
|
||||
//create local vars for clear coding
|
||||
let enabled = newValue
|
||||
let disabled = !newValue
|
||||
if model.disabled != disabled {
|
||||
model.disabled = disabled
|
||||
}
|
||||
|
||||
isUserInteractionEnabled = enabled
|
||||
changeStateNoAnimation(enabled ? isOn : false)
|
||||
setToggleAppearanceFromState()
|
||||
setAccessibilityHint(isEnabled)
|
||||
setAccessibilityHint(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,37 +199,37 @@ import VDSColorTokens
|
||||
}
|
||||
|
||||
/// The state on the toggle. Default value: false.
|
||||
open var isOn: Bool = false {
|
||||
didSet {
|
||||
label.text = isOn ? onText : offText
|
||||
|
||||
if isAnimated {
|
||||
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: {
|
||||
if self.isOn {
|
||||
self.knobView.backgroundColor = self.knobTintColor.on
|
||||
self.toggleView.backgroundColor = self.containerTintColor.on
|
||||
|
||||
} else {
|
||||
self.knobView.backgroundColor = self.knobTintColor.off
|
||||
self.toggleView.backgroundColor = self.containerTintColor.off
|
||||
}
|
||||
}, completion: nil)
|
||||
|
||||
UIView.animate(withDuration: 0.33, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.2, options: [], animations: {
|
||||
open var isOn: Bool {
|
||||
get { model.on }
|
||||
set {
|
||||
if model.on != newValue {
|
||||
model.on = newValue
|
||||
setAccessibilityValue(model.on)
|
||||
if isAnimated {
|
||||
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: {
|
||||
if newValue {
|
||||
self.knobView.backgroundColor = self.knobTintColor.on
|
||||
self.toggleView.backgroundColor = self.containerTintColor.on
|
||||
|
||||
} else {
|
||||
self.knobView.backgroundColor = self.knobTintColor.off
|
||||
self.toggleView.backgroundColor = self.containerTintColor.off
|
||||
}
|
||||
}, completion: nil)
|
||||
|
||||
UIView.animate(withDuration: 0.33, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.2, options: [], animations: {
|
||||
self.constrainKnob()
|
||||
self.knobWidthConstraint?.constant = Self.getKnobScaledSize().width
|
||||
self.layoutIfNeeded()
|
||||
}, completion: nil)
|
||||
|
||||
} else {
|
||||
setToggleAppearanceFromState()
|
||||
self.constrainKnob()
|
||||
self.knobWidthConstraint?.constant = Self.getKnobScaledSize().width
|
||||
self.layoutIfNeeded()
|
||||
}, completion: nil)
|
||||
|
||||
} else {
|
||||
setToggleAppearanceFromState()
|
||||
self.constrainKnob()
|
||||
}
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
model?.on = isOn
|
||||
setAccessibilityValue(isOn)
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,12 +276,21 @@ import VDSColorTokens
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setup()
|
||||
}
|
||||
|
||||
public convenience override init() {
|
||||
self.init(frame: .zero)
|
||||
setup()
|
||||
}
|
||||
|
||||
|
||||
func setup() {
|
||||
cancellable = $model.sink { [weak self] viewModel in
|
||||
self?.onStateChange(viewModel: viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
//functions
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
@ -392,19 +484,19 @@ import VDSColorTokens
|
||||
}
|
||||
}
|
||||
|
||||
// MARK:- MoleculeViewProtocol
|
||||
open override func set(with model: ModelType) {
|
||||
self.model = model
|
||||
isOn = model.on
|
||||
changeStateNoAnimation(isOn)
|
||||
|
||||
private func onStateChange(viewModel: ModelType) {
|
||||
isAnimated = true
|
||||
isEnabled = !model.disabled
|
||||
|
||||
guard let font = try? VDSFontStyle.font(for: .body, fontWeight: model.fontWeight, fontSize: model.fontSize) else {
|
||||
return
|
||||
}
|
||||
|
||||
label.font = font
|
||||
isOn = viewModel.on
|
||||
isEnabled = !viewModel.disabled
|
||||
changeStateNoAnimation(viewModel.on)
|
||||
backgroundColor = viewModel.surface == .dark ? VDSColor.backgroundPrimaryDark : .clear
|
||||
label.set(with: viewModel)
|
||||
label.text = viewModel.on ? viewModel.onText : viewModel.offText
|
||||
}
|
||||
|
||||
// MARK:- Modable
|
||||
open func set(with model: ModelType) {
|
||||
self.model = model
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSTypographyTokens
|
||||
|
||||
extension VDSToggle {
|
||||
public enum TextPosition: String, Codable {
|
||||
@ -15,13 +14,17 @@ extension VDSToggle {
|
||||
}
|
||||
}
|
||||
|
||||
public protocol VDSToggleModel: Surfaceable, FormFieldable, DataTrackable, Disabling, Accessable {
|
||||
public protocol VDSToggleModel: VDSLabelModel, FormFieldable, DataTrackable, Disabling, Accessable {
|
||||
var id: String? { get set }
|
||||
var showText: Bool { get set }
|
||||
var on: Bool { get set }
|
||||
var fontSize: VDSFontSize { get set }
|
||||
var textPosition: VDSTextPosition { get set }
|
||||
var fontWeight: VDSFontWeight { get set }
|
||||
var offText: String { get set }
|
||||
var onText: String { get set }
|
||||
}
|
||||
|
||||
extension VDSToggleModel {
|
||||
public var fontCategory: VDSFontCategory {
|
||||
get { return .body }
|
||||
set { return }
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user