diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b54ad255..6f4709e4 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ 0ABD136B237B193A0081388D /* FormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD136A237B193A0081388D /* FormView.swift */; }; 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */; }; 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; }; + 0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.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 */; }; @@ -243,6 +244,7 @@ 0ABD136A237B193A0081388D /* FormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormView.swift; sourceTree = ""; }; 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = ""; }; 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = ""; }; + 0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.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 = ""; }; @@ -915,6 +917,7 @@ children = ( D2B18B7E2360913400A9AEDC /* Control.swift */, D2B18B802360945C00A9AEDC /* View.swift */, + 0AE14F63238315D2005417F8 /* TextField.swift */, ); path = BaseClasses; sourceTree = ""; @@ -1162,6 +1165,7 @@ D224798A2314445E003FCCF9 /* LabelSwitch.swift in Sources */, D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, + 0AE14F64238315D2005417F8 /* TextField.swift in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */, D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */, diff --git a/MVMCoreUI/Atoms/TextFields/DateDropdownEntryField.swift b/MVMCoreUI/Atoms/TextFields/DateDropdownEntryField.swift index 965c5495..97bb8740 100644 --- a/MVMCoreUI/Atoms/TextFields/DateDropdownEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/DateDropdownEntryField.swift @@ -41,9 +41,9 @@ open class DateDropdownEntryField: DropdownEntryField { public override init(frame: CGRect) { super.init(frame: frame) - MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: textField.delegate) datePicker = MVMCoreUICommonViewsUtility.addDatePicker(to: textField) datePicker?.timeZone = NSTimeZone.system + MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: textField.delegate) } public convenience init() { diff --git a/MVMCoreUI/Atoms/TextFields/DropdownEntryField.swift b/MVMCoreUI/Atoms/TextFields/DropdownEntryField.swift index 04f8dacb..a9d5d693 100644 --- a/MVMCoreUI/Atoms/TextFields/DropdownEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/DropdownEntryField.swift @@ -74,7 +74,6 @@ import UIKit } } - // MARK: - Molecular extension DropdownEntryField { @@ -88,18 +87,3 @@ extension DropdownEntryField { } } } - -// MARK: - Accessibility -extension DropdownEntryField { - - open override func setAccessibilityString(_ accessibilityString: String?) { - - var accessibilityString = accessibilityString ?? "" - - if let textPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") { - accessibilityString += textPickerItem - } - - textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")" - } -} diff --git a/MVMCoreUI/Atoms/TextFields/ItemDropdownEntryField.swift b/MVMCoreUI/Atoms/TextFields/ItemDropdownEntryField.swift index 12c5cedd..33345a55 100644 --- a/MVMCoreUI/Atoms/TextFields/ItemDropdownEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/ItemDropdownEntryField.swift @@ -17,19 +17,38 @@ open class ItemDropdownEntryField: DropdownEntryField { public var pickerData: [String] = [] public var pickerView: UIPickerView? + public var componentsCount = 1 + + /// When selecting first responder, allow initial selected value to appear in empty text field. + public var setInitialValueInTextField = true + + //-------------------------------------------------- + // MARK: - Delegate + //-------------------------------------------------- + + /// Holds a reference to the delegating class so this class can internally influence the TextField behavior as well. + private weak var outsiderTextDelegate: UITextFieldDelegate? + + /// If you're using a MFViewController, you must set this to it + public override weak var uiTextFieldDelegate: UITextFieldDelegate? { + get { return textField.delegate } + set { + textField.delegate = self + outsiderTextDelegate = newValue + } + } + //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- - public convenience init() { - self.init(frame: .zero) - } - public convenience init(pickerData: [String]) { self.init(frame: .zero) self.pickerData = pickerData pickerView = MVMCoreUICommonViewsUtility.addPicker(to: textField, delegate: self) + textField.hideBlinkingCaret = true + uiTextFieldDelegate = self } //-------------------------------------------------- @@ -41,13 +60,26 @@ open class ItemDropdownEntryField: DropdownEntryField { pickerView?.delegate = delegate pickerView?.dataSource = delegate } + + private func setInitialValueFromPicker() { + + if setInitialValueInTextField, let pickerIndex = pickerView?.selectedRow(inComponent: 0) { + text = pickerData[pickerIndex] + } + } + + @objc override func startEditing() { + super.startEditing() + + setInitialValueFromPicker() + } } // MARK:- Base Picker Delegate extension ItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource { public func numberOfComponents(in pickerView: UIPickerView) -> Int { - return 1 + return componentsCount } public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { @@ -59,7 +91,7 @@ extension ItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource { } public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { - textField.text = pickerData[row] + text = pickerData[row] } } @@ -72,3 +104,28 @@ extension ItemDropdownEntryField { guard let dictionary = json, !dictionary.isEmpty else { return } } } + +// MARK: - UITextField Intercept +extension ItemDropdownEntryField { + + public func textFieldDidBeginEditing(_ textField: UITextField) { + + setInitialValueFromPicker() + outsiderTextDelegate?.textFieldDidBeginEditing?(textField) + } +} + +// MARK: - Accessibility +extension DropdownEntryField { + + open override func setAccessibilityString(_ accessibilityString: String?) { + + var accessibilityString = accessibilityString ?? "" + + if let textPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") { + accessibilityString += textPickerItem + } + + textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")" + } +} diff --git a/MVMCoreUI/Atoms/TextFields/TextEntryField.swift b/MVMCoreUI/Atoms/TextFields/TextEntryField.swift index 49d9b1e3..1c783cd4 100644 --- a/MVMCoreUI/Atoms/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/TextEntryField.swift @@ -24,10 +24,9 @@ import UIKit // MARK: - Outlets //-------------------------------------------------- - public private(set) var textField: UITextField = { - let textField = UITextField(frame: .zero) + public private(set) var textField: TextField = { + let textField = TextField(frame: .zero) textField.isAccessibilityElement = true - textField.translatesAutoresizingMaskIntoConstraints = false textField.setContentCompressionResistancePriority(.required, for: .vertical) textField.font = MFStyler.fontForTextField() textField.smartQuotesType = .no @@ -201,6 +200,7 @@ import UIKit override open func resignFirstResponder() -> Bool { textField.resignFirstResponder() + isSelected = false return true } @@ -247,7 +247,7 @@ import UIKit @objc func startEditing() { - entryContainer.originalUI() + isSelected = true textField.becomeFirstResponder() } } diff --git a/MVMCoreUI/BaseClasses/TextField.swift b/MVMCoreUI/BaseClasses/TextField.swift new file mode 100644 index 00000000..2fdc9e4e --- /dev/null +++ b/MVMCoreUI/BaseClasses/TextField.swift @@ -0,0 +1,93 @@ +// +// TextField.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 11/18/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + + +open class TextField: UITextField { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + open var json: [AnyHashable: Any]? + + private var initialSetupPerformed = false + + /// Set to true to hide the blinking textField cursor. + public var hideBlinkingCaret = false + + //-------------------------------------------------- + // MARK: - Initialization + //-------------------------------------------------- + + public override init(frame: CGRect) { + super.init(frame: .zero) + initialSetup() + } + + public convenience init() { + self.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + initialSetup() + } + + public func initialSetup() { + + if !initialSetupPerformed { + initialSetupPerformed = true + setupView() + } + } + + open override func caretRect(for position: UITextPosition) -> CGRect { + + if hideBlinkingCaret { + return .zero + } + + return super.caretRect(for: position) + } +} + +/// MARK:- MVMCoreViewProtocol +extension TextField: MVMCoreViewProtocol { + + open func updateView(_ size: CGFloat) {} + + /// Will be called only once. + open func setupView() { + translatesAutoresizingMaskIntoConstraints = false + insetsLayoutMarginsFromSafeArea = false + } +} + + +/// MARK:- MVMCoreUIMoleculeViewProtocol +extension TextField: MVMCoreUIMoleculeViewProtocol { + + open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + self.json = json + + guard let dictionary = json else { return } + + if let backgroundColorString = dictionary.optionalStringForKey(KeyBackgroundColor) { + backgroundColor = UIColor.mfGet(forHex: backgroundColorString) + } + + if let text = dictionary[KeyText] as? String { + self.text = text + } + } + + open func reset() { + backgroundColor = .clear + } +}