Reworked bezier logic for CaretView. It was not optimal.

This commit is contained in:
Kevin G Christiano 2019-11-01 16:15:19 -04:00
parent 5e96653d4b
commit 475d08296b
8 changed files with 300 additions and 285 deletions

View File

@ -25,8 +25,6 @@ import UIKit
return layer
}()
weak var textBoxDelegate: DigitBoxDelegate?
private var previousSize: CGFloat = 0.0
/// Determines if a border should be drawn.
@ -36,6 +34,12 @@ import UIKit
private var borderStrokeColor: UIColor = .mfSilver()
private var borderPath: UIBezierPath = UIBezierPath()
//--------------------------------------------------
// MARK: - Delegate
//--------------------------------------------------
weak var textBoxDelegate: DigitBoxDelegate?
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
@ -47,11 +51,6 @@ import UIKit
// MARK: - Initializers
//--------------------------------------------------
required public init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("DigitBox has not been implemented")
}
public override init(frame: CGRect) {
super.init(frame: frame)
setup()
@ -61,11 +60,16 @@ import UIKit
self.init(frame: .zero)
}
required public init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("DigitBox has not been implemented")
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
func setup() {
private func setup() {
guard constraints.isEmpty else { return }
@ -74,7 +78,7 @@ import UIKit
textAlignment = .center
keyboardType = .numberPad
layer.borderWidth = 1
showError(false)
showErrorState(false)
widthConstraint = widthAnchor.constraint(equalToConstant: 39)
widthConstraint?.isActive = true
@ -83,7 +87,6 @@ import UIKit
heightConstraint?.isActive = true
layer.addSublayer(bottomBar)
updateView(MVMCoreUISplitViewController.getDetailViewWidth())
}
@ -161,7 +164,7 @@ import UIKit
}
}
func showError(_ show: Bool) {
func showErrorState(_ show: Bool) {
showError = show
borderStrokeColor = show ? .mfPumpkin() : .mfSilver()

View File

@ -8,7 +8,10 @@
import UIKit
/**
* Subclass of TextEntryField due to the conveniences provided.
* TODO: Compare overrides to determine if TextEntryField is necessary.
*/
@objcMembers open class DigitEntryField: TextEntryField, DigitBoxDelegate {
//--------------------------------------------------
// MARK: - Outlets
@ -20,69 +23,65 @@ import UIKit
// MARK: - Properties
//--------------------------------------------------
private var numberOfDigits = 0
private var numberOfDigits = 4
private var switchedAutomatically = false
public var digitFields: [DigitBox]?
public var digitFields: [DigitBox] = []
public override var isEnabled: Bool {
didSet {
if isEnabled {
titleLabel.styleB2(true)
} else {
titleLabel.textColor = UIColor.mfBattleshipGrey()
titleLabel.textColor = .mfBattleshipGrey()
}
for textField in digitFields ?? [] {
for textField in digitFields {
textField.isUserInteractionEnabled = isEnabled
textField.isEnabled = isEnabled
textField.textColor = isEnabled ? .black : UIColor.mfBattleshipGrey()
textField.textColor = isEnabled ? .black : .mfBattleshipGrey()
}
}
}
/// Sets placeholder text in the textField.
public override var feedback: String? {
public override var placeholder: String? {
get {
var string = ""
for digitField in digitFields ?? [] {
if let digitext = digitField.attributedPlaceholder?.string {
string += digitext
}
}
digitFields.forEach { string += $0.attributedPlaceholder?.string ?? "" }
return !string.isEmpty ? string : nil
}
set {
guard let fieldValue = newValue, let fields = digitFields else { return }
guard let newValue = newValue else { return }
for (index, field) in fields.enumerated() {
if index < fieldValue.count {
let stringForIndex = (newValue as NSString?)?.substring(with: NSRange(location: index, length: 1))
field.attributedPlaceholder = NSAttributedString(string: stringForIndex ?? "", attributes: [
for (index, field) in digitFields.enumerated() {
if index < newValue.count {
let indexChar = newValue.index(newValue.startIndex, offsetBy: index)
field.attributedPlaceholder = NSAttributedString(string: String(newValue[indexChar]), attributes: [
NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()])
}
}
//
// if feedback.text.length > 0 {
// labelToTextFieldPin?.constant = 10
// } else {
// labelToTextFieldPin?.constant = 0
// }
// adding missing accessibilityLabel value
// if we have some value in accessibilityLabel,
// then only can append regular and picker item
// textField.accessibilityLabel() = newValue ?? "" + (MVMCoreUIUtility.hardcodedString(withKey: "mfdigittextfield_regular"))
//
// super.showErrorMessage(errorMessage)
//
// if self.showErrorMessage {
// self.labelToTextFieldPin?.constant = 10
// }
// for field in self.digitFields ?? [] {
// field.setAsError()
// }
// If there is already text in the textfield, set the place holder label below.
if let text = text, !text.isEmpty && !showError {
feedback = placeholder
} else if !showError {
feedback = ""
}
if let feedback = feedback, !feedback.isEmpty {
feedbackContainerDistance?.constant = 10
} else {
feedbackContainerDistance?.constant = 0
}
/*
* adding missing accessibilityLabel value
* if we have some value in accessibilityLabel,
* then only can append regular and picker item
*/
textField.accessibilityLabel = newValue + (MVMCoreUIUtility.hardcodedString(withKey: "mfdigittextfield_regular") ?? "")
}
}
@ -90,21 +89,17 @@ import UIKit
get {
var string = ""
for digitField in digitFields ?? [] {
if let digitText = digitField.text {
string += digitText
}
}
digitFields.forEach { string += $0.text ?? "" }
return string
}
set {
guard let fields = self.digitFields else { return }
guard let newValue = newValue else { return }
for (index, field) in fields.enumerated() {
if index < (text?.count ?? 0) {
let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: index, length: 1))
field.text = stringForIndex
for (index, field) in digitFields.enumerated() {
if index < newValue.count {
let indexChar = newValue.index(newValue.startIndex, offsetBy: index)
field.text = String(newValue[indexChar])
}
}
@ -116,9 +111,9 @@ import UIKit
get { return titleLabel.text }
set {
if let formText = newValue, !formText.isEmpty {
messageToTextFieldPin?.constant = 10
titleContainerDistance?.constant = 10
} else {
messageToTextFieldPin?.constant = 0
titleContainerDistance?.constant = 0
}
super.title = newValue
@ -131,21 +126,17 @@ import UIKit
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
for field in self.digitFields ?? [] {
field.showError(false)
if self.showError {
self.feedbackContainerDistance?.constant = 10
self.setNeedsLayout()
}
self.digitFields.forEach { $0.showErrorState(true) }
}
}
}
}
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
private weak var messageToTextFieldPin: NSLayoutConstraint?
private weak var labelToTextFieldPin: NSLayoutConstraint?
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -185,6 +176,7 @@ import UIKit
open func setup() {
hideBorder = true
titleLabel.styleB2(true)
alignCenterHorizontal()
}
@ -206,16 +198,11 @@ import UIKit
self.titleLabel.updateView(size)
if let digitFields = self.digitFields, !digitFields.isEmpty {
// Remove all current UI.
StackableViewController.remove(digitFields)
// Update text boxes.
for digitField in digitFields {
digitField.updateView(size)
}
if !self.digitFields.isEmpty {
StackableViewController.remove(self.digitFields)
self.digitFields.forEach { $0.updateView(size) }
}
// Layout text boxes.
@ -227,6 +214,14 @@ import UIKit
// MARK: - Methods
//--------------------------------------------------
func removeError() {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.digitFields.forEach { $0.showErrorState(false) }
}
}
func createDigitField() -> DigitBox {
let textField = DigitBox()
@ -239,22 +234,20 @@ import UIKit
func buildTextFieldsView(size: CGFloat) {
// Remove all current UI.
if let digitFields = digitFields, !digitFields.isEmpty {
if !digitFields.isEmpty {
StackableViewController.remove(digitFields)
}
if numberOfDigits > 0 {
let digitFields = [DigitBox](repeating: createDigitField(), count: numberOfDigits)
for digitField in digitFields {
digitField.updateView(size)
}
digitFields.forEach { $0.updateView(size) }
self.digitFields = digitFields
setupTextFieldsView(forSize: size)
} else {
digitFields = nil
digitFields = []
}
}
@ -265,10 +258,10 @@ import UIKit
guard let self = self else { return }
if let feedback = self.feedback, !feedback.isEmpty {
self.labelToTextFieldPin?.constant = 10
self.feedbackContainerDistance?.constant = 10
} else {
self.labelToTextFieldPin?.constant = 0
self.feedbackContainerDistance?.constant = 0
}
}
}
@ -276,15 +269,13 @@ import UIKit
func setAsSecureTextEntry(_ secureEntry: Bool) {
DispatchQueue.main.async { [weak self] in
guard let self = self,
let fields = self.digitFields
else { return }
guard let self = self else { return }
for (index, field) in fields.enumerated() {
for (index, field) in self.digitFields.enumerated() {
field.isSecureTextEntry = secureEntry
// Accessibility - 33704 fix voice over will read what pin user is filling
field.accessibilityLabel = String(format: "PIN %lu of %lu", UInt(index) + 1, UInt(fields.count))
field.accessibilityLabel = String(format: "PIN %lu of %lu", UInt(index) + 1, UInt(self.digitFields.count))
}
}
}
@ -292,24 +283,21 @@ import UIKit
func setupTextFieldsView(forSize size: CGFloat) {
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(),
let digitFieldsView = digitFieldsView,
let digitFields = digitFields
let digitFieldsView = digitFieldsView
else { return }
StackableViewController.populateViewHorizontally(digitFieldsView, withUIArray: digitFields, withSpacingBlock: { object in
var inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space)
guard let digitFields = self.digitFields else { return inset }
if digitFields.count == 1 {
if self.digitFields.count == 1 {
inset.left = 0
inset.right = 0
} else if let field = object as? UITextField, field == digitFields.first {
} else if let field = object as? UITextField, field == self.digitFields.first {
inset.left = 0
} else if let field = object as? UITextField, field == digitFields.last {
} else if let field = object as? UITextField, field == self.digitFields.last {
inset.right = 0
}
@ -319,57 +307,18 @@ import UIKit
public override func defaultValidationBlock() {
weak var weakSelf = self
validationBlock = { enteredValue in
if (enteredValue?.count ?? 0) > 0 && (enteredValue?.count ?? 0) == weakSelf?.digitFields?.count {
return true
}
return false
guard let enteredValue = enteredValue else { return false }
return enteredValue.count > 0 && enteredValue.count == self.digitFields.count
}
}
//--------------------------------------------------
// MARK: - Molecule
//--------------------------------------------------
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
guard let dictionary = json else { return }
let digits = dictionary["digits"] as? Int ?? 4
if digits != numberOfDigits {
numberOfDigits = digits
}
if !dictionary.isEmpty{
for textField in digitFields ?? [] {
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegateObject as? UITextFieldDelegate)
}
}
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 44
}
//--------------------------------------------------
// MARK: - Helpers
//--------------------------------------------------
func selectPreviousTextField(_ currentTextField: UITextField?, clear: Bool) {
var selectNextField = false
guard let fields = digitFields else { return }
for field in fields {
for field in digitFields {
if field == currentTextField {
selectNextField = true
@ -390,18 +339,16 @@ import UIKit
var selectNextField = false
guard let fields = digitFields else { return }
for field in fields{
for field in digitFields {
if field == currentTextField {
selectNextField = true
} else if selectNextField {
if !clear {
self.switchedAutomatically = true
switchedAutomatically = true
}
field.becomeFirstResponder()
self.switchedAutomatically = false
switchedAutomatically = false
UIAccessibility.post(notification: .layoutChanged, argument: field)
}
@ -409,20 +356,46 @@ import UIKit
}
//--------------------------------------------------
// MARK: - Accessinility
// MARK: - Molecule
//--------------------------------------------------
open override class func accessibilityElements() -> [Any]? {
// self.digit
// if let digitFields = self.digitFields {
// return [digitFields] + [textField]
// }
//
return [textField]
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
guard let dictionary = json else { return }
let digits = dictionary["digits"] as? Int ?? 4
if digits != numberOfDigits {
numberOfDigits = digits
}
if !dictionary.isEmpty{
for textField in digitFields {
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegateObject as? UITextFieldDelegate)
}
}
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 44
}
//--------------------------------------------------
// MARK: - TextFieldDelegate
// MARK: - Accessibility
//--------------------------------------------------
open override class func accessibilityElements() -> [Any]? {
// let fields = []
// return self.digitFields
return nil
}
//--------------------------------------------------
// MARK: - Text Field Delegate
//--------------------------------------------------
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
@ -495,7 +468,10 @@ import UIKit
return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true
}
//--------------------------------------------------
// MARK: - Passed Along TextField delegate
//--------------------------------------------------
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true

View File

@ -14,23 +14,19 @@ import UIKit
// MARK: - Outlets
//--------------------------------------------------
let dropDownCaretLabel: Label = {
let label = Label()
label.setContentHuggingPriority(UILayoutPriority(900), for: .horizontal)
label.setContentHuggingPriority(UILayoutPriority(251), for: .vertical)
label.setContentCompressionResistancePriority(UILayoutPriority(900), for: .horizontal)
label.isHidden = true
label.isUserInteractionEnabled = true
return label
let dropDownCaretLabel: CaretView = {
let caret = CaretView()
caret.isHidden = true
caret.isUserInteractionEnabled = true
return caret
}()
private var calendar: Calendar?
//--------------------------------------------------
// MARK: - Accessories
//--------------------------------------------------
public weak var datePicker: UIDatePicker?
private var calendar: Calendar?
//--------------------------------------------------
// MARK: - Properties
@ -39,9 +35,7 @@ import UIKit
public var dropDownIsDisplayed = false
public override var isEnabled: Bool {
didSet {
showDropDown(isEnabled)
}
didSet { showDropDown(isEnabled) }
}
//--------------------------------------------------
@ -56,10 +50,9 @@ import UIKit
public override init(frame: CGRect) {
super.init(frame: frame)
setupView()
setup()
}
/// Basic initializer.
public convenience init() {
self.init(frame: .zero)
}
@ -68,7 +61,7 @@ import UIKit
public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
super.init(frame: .zero)
setupView()
setup()
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: bothDelegates)
setBothTextDelegates(to: bothDelegates)
}
@ -78,6 +71,13 @@ import UIKit
fatalError("DropdownEntryField does not support xib.")
}
private func setup() {
dropDownCaretLabel.heightAnchor.constraint(equalToConstant: 40).isActive = true
dropDownCaretWidth = widthAnchor.constraint(equalToConstant: 40)
dropDownCaretWidth?.isActive = true
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
@ -116,7 +116,7 @@ import UIKit
override func startEditing() {
super.startEditing()
showDropDown(!showErrorMessage)
showDropDown(!showError)
}
class func getEnabledTextfields(_ textFieldToDetermine: [TextEntryField]?) -> [AnyHashable]? {

View File

@ -43,6 +43,22 @@ import UIKit
return view
}()
//--------------------------------------------------
// MARK: - Delegate
//--------------------------------------------------
weak var delegateObject: MVMCoreUIDelegateObject?
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var isValid = false
public var fieldKey: String?
/// Determines if a border should be drawn.
var hideBorder = false
private var borderStrokeColor: UIColor = .mfSilver()
private var borderPath: UIBezierPath = UIBezierPath()
@ -55,21 +71,9 @@ import UIKit
return layer
}()
weak var delegateObject: MVMCoreUIDelegateObject?
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var isValid = false
public var fieldKey: String?
/// Determines if a border should be drawn.
private var hideBorder = false
public private(set) var appearance: Appearance = .original
public var showErrorMessage = false
public var showError = false
public var errorMessage: String?
@ -133,6 +137,9 @@ import UIKit
public var titleLabelLeading: NSLayoutConstraint?
public var titleLabelTrailing: NSLayoutConstraint?
public var titleContainerDistance: NSLayoutConstraint?
public var feedbackContainerDistance: NSLayoutConstraint?
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -150,7 +157,7 @@ import UIKit
public init(title: String) {
super.init(frame: .zero)
setupView()
self.titleLabel.text = title
titleLabel.text = title
}
required public init?(coder: NSCoder) {
@ -182,7 +189,8 @@ import UIKit
addSubview(fieldContainer)
setupFieldContainerContent(fieldContainer)
fieldContainer.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4).isActive = true
titleContainerDistance = fieldContainer.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4)
titleContainerDistance?.isActive = true
fieldContainerLeading = fieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
fieldContainerLeading?.isActive = true
fieldContainerTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: fieldContainer.trailingAnchor)
@ -190,7 +198,8 @@ import UIKit
addSubview(feedbackLabel)
feedbackLabel.topAnchor.constraint(equalTo: fieldContainer.bottomAnchor, constant: PaddingOne).isActive = true
feedbackContainerDistance = feedbackLabel.topAnchor.constraint(equalTo: fieldContainer.bottomAnchor, constant: PaddingOne)
feedbackContainerDistance?.isActive = true
feedbackLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
feedbackLabelLeading?.isActive = true
feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor)
@ -203,10 +212,8 @@ import UIKit
layoutIfNeeded()
}
/**
Method to override.
Intended to add the interactive content (i.e. textField) to the fieldContainer.
*/
/// Method to override.
/// Intended to add the interactive content (i.e. textField) to the fieldContainer.
open func setupFieldContainerContent(_ container: UIView) {
// To be overridden by subclass.
}
@ -237,7 +244,7 @@ import UIKit
open func refreshBorderUI(bottomBarSize: CGFloat? = nil) {
let size = CGFloat(appearance == .error ? 4 : 1)
let size: CGFloat = appearance == .error ? 4 : 1
bottomBar.frame = CGRect(x: 0, y: fieldContainer.bounds.height - size, width: fieldContainer.bounds.width, height: size)
self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self)
@ -274,11 +281,6 @@ import UIKit
layoutIfNeeded()
}
func resizeBottomBar(size: CGFloat) {
bottomBar.frame = CGRect(x: 0, y: fieldContainer.bounds.height - size, width: fieldContainer.bounds.width, height: size)
}
//--------------------------------------------------
// MARK: - Constraint Methods
//--------------------------------------------------
@ -313,37 +315,30 @@ import UIKit
self.appearance = appearance
isUserInteractionEnabled = true
titleLabel.textColor = .mfBattleshipGrey()
hideBorder = false
feedback = showError ? errorMessage : nil
switch appearance {
case .original:
borderStrokeColor = .mfSilver()
feedback = nil
bottomBar.backgroundColor = UIColor.black.cgColor
titleLabel.textColor = .mfBattleshipGrey()
case .error:
borderStrokeColor = .mfPumpkin()
titleLabel.textColor = UIColor.mfBattleshipGrey()
bottomBar.backgroundColor = UIColor.mfPumpkin().cgColor
feedback = showErrorMessage ? errorMessage : nil
case .lock:
isUserInteractionEnabled = false
hideBorder = true
feedback = nil
titleLabel.textColor = UIColor.mfBattleshipGrey()
bottomBar.backgroundColor = UIColor.clear.cgColor
case .select:
borderStrokeColor = .black
feedback = nil
titleLabel.textColor = UIColor.mfBattleshipGrey()
bottomBar.backgroundColor = UIColor.black.cgColor
case .disable:
isUserInteractionEnabled = false
feedback = nil
borderStrokeColor = .mfSilver()
titleLabel.textColor = self.isEnabled ? UIColor.mfBattleshipGrey() : UIColor.mfSilver()
bottomBar.backgroundColor = self.isEnabled ? UIColor.black.cgColor : UIColor.mfSilver().cgColor

View File

@ -20,8 +20,6 @@ import MVMCore
public var isNationalMdn = true
public var shouldValidateMDN = false
// public var pickerView: UIPickerView?
public var mdn: String? {
get { return MVMCoreUIUtility.removeMdnFormat(text) }
set { text = MVMCoreUIUtility.formatMdn(newValue) }
@ -40,6 +38,13 @@ import MVMCore
self.init(frame: .zero)
}
/// - parameter bothDelegates: Sets both MF/UI Text Field Delegates.
public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
super.init(frame: .zero)
setup()
setBothTextDelegates(to: bothDelegates)
}
required public init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("MdnEntryField xib not supported.")
@ -65,7 +70,7 @@ import MVMCore
// MARK: - Methods
//--------------------------------------------------
func hasValidMDN() -> Bool {
public func hasValidMDN() -> Bool {
guard let MDN = mdn,
!MDN.isEmpty
@ -78,7 +83,7 @@ import MVMCore
return MVMCoreUIUtility.validateInternationalMDNString(MDN)
}
func validateAndColor() -> Bool {
public func validateAndColor() -> Bool {
if !shouldValidateMDN {
let isValid = hasValidMDN()
@ -107,7 +112,7 @@ import MVMCore
}
//--------------------------------------------------
// MARK: - ContactPicker Delegate
// MARK: - Contact Picker Delegate
//--------------------------------------------------
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
@ -127,7 +132,7 @@ import MVMCore
}
text = unformattedMDN
textFieldShouldReturn(textField)
_ = textFieldShouldReturn(textField)
textFieldDidEndEditing(textField)
}
}
@ -136,15 +141,14 @@ import MVMCore
// MARK: - Implemented TextField Delegate
//--------------------------------------------------
@discardableResult
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return uiTextFieldDelegate?.textFieldShouldReturn?(textField) ?? true
}
@objc public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
return false
@ -172,17 +176,17 @@ import MVMCore
// MARK: - Passed Along TextField delegate
//--------------------------------------------------
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true
}
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
return uiTextFieldDelegate?.textFieldShouldEndEditing?(textField) ?? true
}
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
public func textFieldShouldClear(_ textField: UITextField) -> Bool {
return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true
}

View File

@ -65,15 +65,11 @@ import UIKit
public var placeholder: String? {
get { return textField.placeholder }
set {
textField.placeholder = newValue
}
set { textField.placeholder = newValue }
}
public var validationBlock: ((_ value: String?) -> Bool)? {
didSet {
valueChanged()
}
didSet { valueChanged() }
}
public override var errorMessage: String? {
@ -174,6 +170,21 @@ import UIKit
open func clearErrorState() {
/*
[MVMCoreDispatchUtility performBlockOnMainThread:^{
self.separatorHeightConstraint.constant = 1;
self.separatorView.backgroundColor = [UIColor blackColor];
[self layoutIfNeeded];
self.errorShowing = NO;
self.label.textColor = [UIColor blackColor];
self.label.text = @"";
self.textField.accessibilityValue = nil;
[self setNeedsDisplay];
[self layoutIfNeeded];
}];
*/
textField.accessibilityValue = nil
updateUI(appearance: .original)
}
@ -202,7 +213,7 @@ import UIKit
@objc func valueChanged() {
if !showErrorMessage {
if !showError {
feedback = ""
}
@ -217,10 +228,7 @@ import UIKit
} else if !previousValidity && isValid {
clearErrorState()
if let mfTextFieldDelegate = mfTextFieldDelegate {
mfTextFieldDelegate.isValid?(textfield: self)
}
mfTextFieldDelegate?.isValid?(textfield: self)
}
}
@ -228,6 +236,7 @@ import UIKit
if isValid {
clearErrorState()
bottomBar.backgroundColor = UIColor.black.cgColor
} else if let errMessage = errorMessage {
feedback = errMessage
@ -236,6 +245,10 @@ import UIKit
@objc func startEditing() {
if appearance != .original {
updateUI(appearance: .original)
}
textField.becomeFirstResponder()
}
}

View File

@ -2,52 +2,53 @@
// CaretView.swift
// MobileFirstFramework
//
// Created by Kolli, Praneeth on 1/5/18.
// Converted by Christiano, Kevin on 1/5/18.
// Created by Christiano, Kevin on 1/5/18.
// Copyright © 2018 Verizon Wireless. All rights reserved.
//
open class CaretView: MFView {
@objcMembers open class CaretView: MFView {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
// Objc can't use float enum.
@objc public static let thin: CGFloat = 6.0
@objc public static let standard: CGFloat = 2.6
@objc public static let thick: CGFloat = 1.5
public static let thin: CGFloat = 6.0
public static let standard: CGFloat = 2.5
public static let thick: CGFloat = 1.5
public var strokeColor: UIColor = .black
public var lineWidth: CGFloat = 1
public var direction: Direction = .right
private var caretPath: UIBezierPath = UIBezierPath()
private(set) var strokeColor: UIColor?
private var lineWidth: CGFloat?
private var lineThickness: CGFloat?
//------------------------------------------------------
// MARK: - Initialization
//------------------------------------------------------
@objc public init() {
super.init(frame: .zero)
}
@objc public override init(frame: CGRect) {
super.init(frame: frame)
}
@objc required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
@objc public init() {
super.init(frame: .zero)
}
/// Can init with a specific line width.
@objc public init(lineWidth: CGFloat) {
super.init(frame: CGRect())
super.init(frame: .zero)
self.lineWidth = lineWidth
}
/// Can init with a specific line thickness, scales based on width and height.
@objc public init(lineThickness: CGFloat) {
super.init(frame: CGRect())
self.lineThickness = lineThickness
super.init(frame: .zero)
// self.lineThickness = lineThickness
}
@objc required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("CaretView xib not supported.")
}
@objc override open func setupView() {
@ -55,9 +56,60 @@ open class CaretView: MFView {
}
//------------------------------------------------------
// MARK: - Private Function
// MARK: - Drawing
//------------------------------------------------------
/// The direction the caret will be pointing to.
public enum Direction: String {
case left
case right
case down
case up
}
@objc override open func draw(_ rect: CGRect) {
super.draw(rect)
caretPath.removeAllPoints()
caretPath.lineJoinStyle = .miter
caretPath.lineWidth = lineWidth
let inset = lineWidth / 2
switch direction {
case .up:
caretPath.move(to: CGPoint(x: inset, y: frame.size.height - inset))
caretPath.addLine(to: CGPoint(x: frame.size.width / 2, y: inset))
caretPath.addLine(to: CGPoint(x: frame.size.width, y: frame.size.height))
case .right:
caretPath.move(to: CGPoint(x: inset, y: inset))
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: frame.size.height / 2))
caretPath.addLine(to: CGPoint(x: inset, y: frame.size.height - inset))
case .down:
caretPath.move(to: CGPoint(x: inset, y: inset))
caretPath.addLine(to: CGPoint(x: frame.size.width / 2, y: frame.size.height - inset))
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: inset))
case .left:
caretPath.move(to: CGPoint(x: frame.size.width - inset, y: inset))
caretPath.addLine(to: CGPoint(x: inset, y: frame.size.height / 2))
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: frame.size.height - inset))
}
strokeColor.setStroke()
caretPath.stroke()
}
//------------------------------------------------------
// MARK: - Methods
//------------------------------------------------------
@objc public func setLineColor(_ color: UIColor) {
strokeColor = color
setNeedsDisplay()
}
private func defaultState() {
isOpaque = false
isHidden = false
@ -65,34 +117,6 @@ open class CaretView: MFView {
strokeColor = .black
}
//------------------------------------------------------
// MARK: - Drawing
//------------------------------------------------------
@objc override open func draw(_ rect: CGRect) {
// Drawing Caret
let context = UIGraphicsGetCurrentContext()
context?.clear(rect)
let lineWidthToDraw: CGFloat = lineWidth ?? frame.size.width / (lineThickness ?? 2.6)
let path = UIBezierPath()
path.move(to: CGPoint(x: lineWidthToDraw / 2.0, y: 0.0))
path.addLine(to: CGPoint(x: frame.size.width, y: frame.size.height / 2.0))
path.addLine(to: CGPoint(x: lineWidthToDraw / 2.0, y: frame.size.height))
path.addLine(to: CGPoint(x: 0.0, y: frame.size.height - lineWidthToDraw / 2.0))
path.addLine(to: CGPoint(x: frame.size.width - lineWidthToDraw, y: frame.size.height / 2.0))
path.addLine(to: CGPoint(x: 0.0, y: lineWidthToDraw / 2.0))
path.addLine(to: CGPoint(x: lineWidthToDraw / 2.0, y: 0.0))
strokeColor?.setFill()
path.fill()
path.close()
}
@objc public func setLineColor(_ color: UIColor?) {
strokeColor = color
setNeedsDisplay()
}
//------------------------------------------------------
// MARK: - Atomization
@ -102,10 +126,10 @@ open class CaretView: MFView {
@objc open override func setAsMolecule() {
defaultState()
}
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
// Configure class properties with JSON values
guard let dictionary = json else { return }
if let strokeColorHex = dictionary["strokeColor"] as? String {
@ -115,7 +139,7 @@ open class CaretView: MFView {
if let isHiddenValue = dictionary[KeyIsHidden] as? Bool {
isHidden = isHiddenValue
}
if let isOpaqueValue = dictionary[KeyIsOpaque] as? Bool {
isOpaque = isOpaqueValue
}
@ -130,6 +154,6 @@ open class CaretView: MFView {
}
open override func alignment() -> UIStackView.Alignment {
return UIStackView.Alignment.leading;
return .leading
}
}

View File

@ -31,7 +31,7 @@ open class DashLine: MFView {
required public init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("DashLine xib not supported")
// fatalError("DashLine xib not supported")
}
//------------------------------------------------------