From eab910011ecabb3c4b13a28954450cbfec7a7ccb Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 11 Dec 2019 15:10:26 -0500 Subject: [PATCH] General working order of the Toggle. --- MVMCoreUI.xcodeproj/project.pbxproj | 8 +- .../Views/{Switch.swift => Toggle.swift} | 196 +++++++++--------- .../MVMCoreUIMoleculeMappingObject.m | 2 +- 3 files changed, 102 insertions(+), 104 deletions(-) rename MVMCoreUI/Atoms/Views/{Switch.swift => Toggle.swift} (55%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 33529648..880427d0 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -28,7 +28,7 @@ 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; - 0AA33B3A2398524F0067DD0F /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Switch.swift */; }; + 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; }; 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; }; 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; }; 9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */; }; @@ -227,7 +227,7 @@ 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxWithLabelView.swift; sourceTree = ""; }; - 0AA33B392398524F0067DD0F /* Switch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = ""; }; + 0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; }; 943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = ""; }; 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphViewAnimationHandler.swift; sourceTree = ""; }; 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MVMAnimationFramework.framework; path = ../SharedFrameworks/MVMAnimationFramework.framework; sourceTree = ""; }; @@ -781,7 +781,7 @@ 01004F2F22721C3800991ECC /* RadioButton.swift */, 943784F3236B77BB006A1E82 /* GraphView.swift */, 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */, - 0AA33B392398524F0067DD0F /* Switch.swift */, + 0AA33B392398524F0067DD0F /* Toggle.swift */, ); path = Views; sourceTree = ""; @@ -1085,7 +1085,7 @@ D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */, D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */, D2B18B7F2360913400A9AEDC /* Control.swift in Sources */, - 0AA33B3A2398524F0067DD0F /* Switch.swift in Sources */, + 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */, D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */, DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */, D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/Switch.swift b/MVMCoreUI/Atoms/Views/Toggle.swift similarity index 55% rename from MVMCoreUI/Atoms/Views/Switch.swift rename to MVMCoreUI/Atoms/Views/Toggle.swift index 3fbe1055..0ee42937 100644 --- a/MVMCoreUI/Atoms/Views/Switch.swift +++ b/MVMCoreUI/Atoms/Views/Toggle.swift @@ -1,5 +1,5 @@ // -// Switch.swift +// Toggle.swift // MVMCoreUI // // Created by Kevin Christiano on 12/4/19. @@ -14,33 +14,33 @@ public typealias ActionBlockConfirmation = () -> (Bool) /** A custom implementation of Apple's UISwitch. - Track: The background of the switch control. - Thumb: The circular indicator that slides on the track. + Container: The background of the toggle control. + Knob: The circular indicator that slides on the container. */ -@objcMembers open class Switch: Control, MVMCoreUIViewConstrainingProtocol, FormValidationFormFieldProtocol { +@objcMembers open class Toggle: Control, MVMCoreUIViewConstrainingProtocol, FormValidationFormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public var trackTintColor: (on: UIColor?, off: UIColor?)? = (on: .mfShamrock(), off: .black) - public var thumbTintColor: (on: UIColor?, off: UIColor?)? = (on: .white, off: .white) - public var disabledTintColor: (track: UIColor?, thumb: UIColor?)? = (track: .mfSilver(), thumb: .white) + public var containerTintColor: (on: UIColor?, off: UIColor?)? = (on: .mfShamrock(), off: .black) + public var knobTintColor: (on: UIColor?, off: UIColor?)? = (on: .white, off: .white) + public var disabledTintColor: (container: UIColor?, knob: UIColor?)? = (container: .mfSilver(), knob: .white) public var isAnimated = true - public var didSwitchAction: ActionBlock? - public var shouldSwitchAction: ActionBlockConfirmation? = { + public var didToggleAction: ActionBlock? + public var shouldToggleAction: ActionBlockConfirmation? = { return { return true } }() // Sizes are from InVision design specs. - static let trackSize = CGSize(width: 46, height: 24) - static let thumbSize = CGSize(width: 22, height: 22) + static let containerSize = CGSize(width: 46, height: 24) + static let knobSize = CGSize(width: 22, height: 22) - private var thumbView: View = { + private var knobView: View = { let view = View() view.backgroundColor = .white - view.layer.cornerRadius = Switch.getThumbHeight() / 2.0 + view.layer.cornerRadius = Toggle.getKnobHeight() / 2.0 return view }() @@ -51,8 +51,8 @@ public typealias ActionBlockConfirmation = () -> (Bool) open override var isEnabled: Bool { didSet { isUserInteractionEnabled = isEnabled - backgroundColor = isEnabled ? trackTintColor?.on : disabledTintColor?.track - thumbView.backgroundColor = isEnabled ? thumbTintColor?.on : disabledTintColor?.thumb + backgroundColor = isEnabled ? containerTintColor?.on : disabledTintColor?.container + knobView.backgroundColor = isEnabled ? knobTintColor?.on : disabledTintColor?.knob } } @@ -69,28 +69,25 @@ public typealias ActionBlockConfirmation = () -> (Bool) if isAnimated { UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: { if self.isOn { - self.thumbView.backgroundColor = self.thumbTintColor?.on - self.backgroundColor = self.trackTintColor?.on + self.knobView.backgroundColor = self.knobTintColor?.on + self.backgroundColor = self.containerTintColor?.on } else { - self.thumbView.backgroundColor = self.thumbTintColor?.off - self.backgroundColor = self.trackTintColor?.off + self.knobView.backgroundColor = self.knobTintColor?.off + self.backgroundColor = self.containerTintColor?.off } - }, completion: nil) UIView.animate(withDuration: 0.33, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.2, options: [], animations: { - - self.constrainThumb() - self.thumbWidthConstraint?.constant = Switch.getThumbWidth() + self.constrainKnob() + self.knobWidthConstraint?.constant = Toggle.getKnobWidth() self.layoutIfNeeded() - }, completion: nil) } else { - backgroundColor = isOn ? trackTintColor?.on : trackTintColor?.off - thumbView.backgroundColor = isOn ? thumbTintColor?.on : thumbTintColor?.off - self.constrainThumb() + backgroundColor = isOn ? containerTintColor?.on : containerTintColor?.off + knobView.backgroundColor = isOn ? knobTintColor?.on : knobTintColor?.off + self.constrainKnob() } FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol) @@ -110,17 +107,17 @@ public typealias ActionBlockConfirmation = () -> (Bool) // MARK: - Constraints //-------------------------------------------------- - private var thumbLeadingConstraint: NSLayoutConstraint? - private var thumbTrailingConstraint: NSLayoutConstraint? - private var thumbHeightConstraint: NSLayoutConstraint? - private var thumbWidthConstraint: NSLayoutConstraint? + private var knobLeadingConstraint: NSLayoutConstraint? + private var knobTrailingConstraint: NSLayoutConstraint? + private var knobHeightConstraint: NSLayoutConstraint? + private var knobWidthConstraint: NSLayoutConstraint? private var heightConstraint: NSLayoutConstraint? private var widthConstraint: NSLayoutConstraint? - private func constrainThumb() { + private func constrainKnob() { - self.thumbLeadingConstraint?.isActive = isOn - self.thumbTrailingConstraint?.isActive = !isOn + self.knobLeadingConstraint?.isActive = !isOn + self.knobTrailingConstraint?.isActive = isOn } //-------------------------------------------------- @@ -136,26 +133,26 @@ public typealias ActionBlockConfirmation = () -> (Bool) self.init(frame: .zero) } - public convenience init(isOn: Bool, didSwitchAction: ActionBlock?) { + public convenience init(isOn: Bool, didToggleAction: ActionBlock?) { self.init(frame: .zero) self.isOn = isOn - self.didSwitchAction = didSwitchAction + self.didToggleAction = didToggleAction } - public convenience init(didSwitchAction: ActionBlock?) { + public convenience init(didToggleAction: ActionBlock?) { self.init(frame: .zero) - self.didSwitchAction = didSwitchAction + self.didToggleAction = didToggleAction } - public convenience init(shouldSwitchAction: ActionBlockConfirmation?, didSwitchAction: ActionBlock?) { + public convenience init(shouldToggleAction: ActionBlockConfirmation?, didToggleAction: ActionBlock?) { self.init(frame: .zero) - self.didSwitchAction = didSwitchAction - self.shouldSwitchAction = shouldSwitchAction + self.didToggleAction = didToggleAction + self.shouldToggleAction = shouldToggleAction } public required init?(coder: NSCoder) { super.init(coder: coder) - fatalError("Switch does not support xib.") + fatalError("Toggle does not support xib.") } //-------------------------------------------------- @@ -165,14 +162,14 @@ public typealias ActionBlockConfirmation = () -> (Bool) public override func updateView(_ size: CGFloat) { super.updateView(size) - heightConstraint?.constant = Switch.getTrackHeight() - widthConstraint?.constant = Switch.getTrackWidth() + heightConstraint?.constant = Toggle.getContainerHeight() + widthConstraint?.constant = Toggle.getContainerWidth() - thumbHeightConstraint?.constant = Switch.getThumbHeight() - thumbWidthConstraint?.constant = Switch.getThumbWidth() + knobHeightConstraint?.constant = Toggle.getKnobHeight() + knobWidthConstraint?.constant = Toggle.getKnobWidth() - layer.cornerRadius = Switch.getTrackHeight() / 2.0 - thumbView.layer.cornerRadius = Switch.getThumbHeight() / 2.0 + layer.cornerRadius = Toggle.getContainerHeight() / 2.0 + knobView.layer.cornerRadius = Toggle.getKnobHeight() / 2.0 } public override func setupView() { @@ -180,50 +177,50 @@ public typealias ActionBlockConfirmation = () -> (Bool) guard subviews.isEmpty else { return } - heightConstraint = heightAnchor.constraint(equalToConstant: Switch.trackSize.height) + heightConstraint = heightAnchor.constraint(equalToConstant: Toggle.containerSize.height) heightConstraint?.isActive = true - widthConstraint = widthAnchor.constraint(equalToConstant: Switch.trackSize.width) + widthConstraint = widthAnchor.constraint(equalToConstant: Toggle.containerSize.width) widthConstraint?.isActive = true - layer.cornerRadius = Switch.trackSize.height / 2.0 - backgroundColor = trackTintColor?.off + layer.cornerRadius = Toggle.containerSize.height / 2.0 + backgroundColor = containerTintColor?.off - addSubview(thumbView) + addSubview(knobView) - thumbHeightConstraint = thumbView.heightAnchor.constraint(equalToConstant: Switch.thumbSize.height) - thumbHeightConstraint?.isActive = true - thumbWidthConstraint = thumbView.widthAnchor.constraint(equalToConstant: Switch.thumbSize.width) - thumbWidthConstraint?.isActive = true - thumbView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - thumbView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: thumbView.bottomAnchor).isActive = true + knobHeightConstraint = knobView.heightAnchor.constraint(equalToConstant: Toggle.knobSize.height) + knobHeightConstraint?.isActive = true + knobWidthConstraint = knobView.widthAnchor.constraint(equalToConstant: Toggle.knobSize.width) + knobWidthConstraint?.isActive = true + knobView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + knobView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: knobView.bottomAnchor).isActive = true - thumbTrailingConstraint = trailingAnchor.constraint(equalTo: thumbView.trailingAnchor, constant: 1) - thumbLeadingConstraint = thumbView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 1) - thumbLeadingConstraint?.isActive = true + knobTrailingConstraint = trailingAnchor.constraint(equalTo: knobView.trailingAnchor, constant: 1) + knobLeadingConstraint = knobView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 1) + knobLeadingConstraint?.isActive = true - accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: "Switch_buttonlabel") + accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: "Toggle_buttonlabel") } - class func getTrackWidth() -> CGFloat { - let trackWidth = Switch.trackSize.width - return (MFSizeObject(standardSize: trackWidth, standardiPadPortraitSize: CGFloat(Switch.trackSize.width * 1.5)))?.getValueBasedOnApplicationWidth() ?? trackWidth + class func getContainerWidth() -> CGFloat { + let containerWidth = Toggle.containerSize.width + return (MFSizeObject(standardSize: containerWidth, standardiPadPortraitSize: CGFloat(Toggle.containerSize.width * 1.5)))?.getValueBasedOnApplicationWidth() ?? containerWidth } - class func getTrackHeight() -> CGFloat { - let trackHeight = Switch.trackSize.height - return (MFSizeObject(standardSize: trackHeight, standardiPadPortraitSize: CGFloat(Switch.trackSize.height * 1.5)))?.getValueBasedOnApplicationWidth() ?? trackHeight + class func getContainerHeight() -> CGFloat { + let containerHeight = Toggle.containerSize.height + return (MFSizeObject(standardSize: containerHeight, standardiPadPortraitSize: CGFloat(Toggle.containerSize.height * 1.5)))?.getValueBasedOnApplicationWidth() ?? containerHeight } - class func getThumbWidth() -> CGFloat { - let thumbWidth = Switch.thumbSize.width - return (MFSizeObject(standardSize: thumbWidth, standardiPadPortraitSize: CGFloat(Switch.thumbSize.width * 1.5)))?.getValueBasedOnApplicationWidth() ?? thumbWidth + class func getKnobWidth() -> CGFloat { + let knobWidth = Toggle.knobSize.width + return (MFSizeObject(standardSize: knobWidth, standardiPadPortraitSize: CGFloat(Toggle.knobSize.width * 1.5)))?.getValueBasedOnApplicationWidth() ?? knobWidth } - class func getThumbHeight() -> CGFloat { - let thumbHeight = Switch.thumbSize.width - return (MFSizeObject(standardSize: thumbHeight, standardiPadPortraitSize: CGFloat(Switch.thumbSize.height * 1.5)))?.getValueBasedOnApplicationWidth() ?? thumbHeight + class func getKnobHeight() -> CGFloat { + let knobHeight = Toggle.knobSize.width + return (MFSizeObject(standardSize: knobHeight, standardiPadPortraitSize: CGFloat(Toggle.knobSize.height * 1.5)))?.getValueBasedOnApplicationWidth() ?? knobHeight } //-------------------------------------------------- @@ -240,12 +237,12 @@ public typealias ActionBlockConfirmation = () -> (Bool) toggleAndAction() } - /// This will toggle the state of the Switch and execute the actionBlock if provided. + /// This will toggle the state of the Toggle and execute the actionBlock if provided. public func toggleAndAction() { - if let result = shouldSwitchAction?(), result { + if let result = shouldToggleAction?(), result { isOn.toggle() - didSwitchAction?() + didToggleAction?() } } @@ -263,16 +260,17 @@ public typealias ActionBlockConfirmation = () -> (Bool) open override func touchesBegan(_ touches: Set, with event: UIEvent?) { UIView.animate(withDuration: 0.1, animations: { - self.thumbWidthConstraint?.constant += PaddingOne + self.knobWidthConstraint?.constant += PaddingOne self.layoutIfNeeded() }) } public override func touchesEnded(_ touches: Set, with event: UIEvent?) { - thumbReformAnimation() + knobReformAnimation() - guard let coordinates: CGPoint = touches.first?.location(in: self), + // Action only occurs of the user lifts up from withing acceptable region of the toggle. + guard let coordinates = touches.first?.location(in: self), coordinates.x > -20, coordinates.x < bounds.width + 20, coordinates.y > -20, @@ -284,7 +282,7 @@ public typealias ActionBlockConfirmation = () -> (Bool) public func touchesCancelled(_ touches: Set, with event: UIEvent) { - thumbReformAnimation() + knobReformAnimation() sendActions(for: .touchCancel) } @@ -292,22 +290,23 @@ public typealias ActionBlockConfirmation = () -> (Bool) // MARK: - Animations //-------------------------------------------------- - public func thumbReformAnimation() { + public func knobReformAnimation() { if isAnimated { UIView.animate(withDuration: 0.1, animations: { - self.thumbWidthConstraint?.constant = Switch.getThumbWidth() + self.knobWidthConstraint?.constant = Toggle.getKnobWidth() self.layoutIfNeeded() }, completion: nil) + } else { - thumbWidthConstraint?.constant = Switch.getThumbWidth() + knobWidthConstraint?.constant = Toggle.getKnobWidth() layoutIfNeeded() } } } // MARK: - Accessibility -extension Switch { +extension Toggle { public func formFieldGroupName() -> String? { return json?["groupName"] as? String @@ -315,7 +314,7 @@ extension Switch { } // MARK: - FormValidationProtocol -extension Switch { +extension Toggle { public func isValidField() -> Bool { return isOn && json?["required"] as? Bool ?? false @@ -331,7 +330,7 @@ extension Switch { } // MARK: - MVMCoreUIMoleculeViewProtocol -extension Switch { +extension Toggle { public override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) @@ -342,19 +341,19 @@ extension Switch { guard let dictionary = json else { return } if let color = dictionary["onTintColor"] as? String { - trackTintColor?.on = UIColor.mfGet(forHex: color) + containerTintColor?.on = UIColor.mfGet(forHex: color) } if let color = dictionary["offTintColor"] as? String { - trackTintColor?.off = UIColor.mfGet(forHex: color) + containerTintColor?.off = UIColor.mfGet(forHex: color) } - if let color = dictionary["onThumbTintColor"] as? String { - thumbTintColor?.on = UIColor.mfGet(forHex: color) + if let color = dictionary["onKnobTintColor"] as? String { + knobTintColor?.on = UIColor.mfGet(forHex: color) } - if let color = dictionary["offThumbTintColor"] as? String { - thumbTintColor?.off = UIColor.mfGet(forHex: color) + if let color = dictionary["offKnobTintColor"] as? String { + knobTintColor?.off = UIColor.mfGet(forHex: color) } if let state = dictionary["state"] as? Bool { @@ -364,17 +363,16 @@ extension Switch { } if let actionMap = dictionary.optionalDictionaryForKey("actionMap") { - actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } + didToggleAction = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } } - if let isAnimated = dictionary["state"] as? Bool { + if let isAnimated = dictionary["isAnimated"] as? Bool { self.isAnimated = isAnimated } } public class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - - return Switch.getTrackHeight() + return Toggle.getContainerHeight() } public func needsToBeConstrained() -> Bool { diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 4923f21d..98df5822 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -48,7 +48,7 @@ @"radioButtonLabel": RadioButtonLabel.class, @"listItem": MoleculeTableViewCell.class, @"accordionListItem": AccordionMoleculeTableViewCell.class, - @"switch": Switch.class, + @"toggle": Toggle.class, @"leftRightLabelView": LeftRightLabelView.class, @"actionDetailWithImage": ActionDetailWithImage.class, @"image": MFLoadImageView.class,