more.
This commit is contained in:
parent
88eec2bf9d
commit
6d7c1df7cc
@ -28,10 +28,10 @@ import UIKit
|
|||||||
private var previousSize: CGFloat = 0.0
|
private var previousSize: CGFloat = 0.0
|
||||||
|
|
||||||
/// Determines if a border should be drawn.
|
/// Determines if a border should be drawn.
|
||||||
private var hideBorder = false
|
var hideBorder = false
|
||||||
private var showError = false
|
var showError = false
|
||||||
|
|
||||||
private var borderStrokeColor: UIColor = .mfSilver()
|
var borderStrokeColor: UIColor = .mfSilver()
|
||||||
private var borderPath: UIBezierPath = UIBezierPath()
|
private var borderPath: UIBezierPath = UIBezierPath()
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -10,40 +10,35 @@ import UIKit
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclass of TextEntryField due to the conveniences provided.
|
* Subclass of TextEntryField due to the conveniences provided.
|
||||||
* TODO: Compare overrides to determine if TextEntryField is necessary.
|
|
||||||
*/
|
*/
|
||||||
@objcMembers open class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
@objcMembers open class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public private(set) var digitFieldsView: UIView?
|
public private(set) var digitFieldsStack: UIStackView?
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
private var numberOfDigits = 4
|
private(set) var numberOfDigits = 4
|
||||||
private var switchedAutomatically = false
|
private var switchedAutomatically = false
|
||||||
|
|
||||||
public var digitFields: [DigitBox] = []
|
public var digitFields: [DigitBox] = []
|
||||||
|
|
||||||
public override var isEnabled: Bool {
|
public override var isEnabled: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
if isEnabled {
|
titleLabel.textColor = isEnabled ? .black : .black
|
||||||
titleLabel.textColor = .black
|
|
||||||
} else {
|
|
||||||
titleLabel.textColor = .mfBattleshipGrey()
|
|
||||||
}
|
|
||||||
|
|
||||||
for textField in digitFields {
|
for digitBox in digitFields {
|
||||||
textField.isUserInteractionEnabled = isEnabled
|
digitBox.isUserInteractionEnabled = isEnabled
|
||||||
textField.isEnabled = isEnabled
|
digitBox.isEnabled = isEnabled
|
||||||
textField.textColor = isEnabled ? .black : .mfBattleshipGrey()
|
digitBox.textColor = isEnabled ? .black : .mfBattleshipGrey()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets placeholder text in the textField.
|
|
||||||
public override var placeholder: String? {
|
public override var placeholder: String? {
|
||||||
get {
|
get {
|
||||||
var string = ""
|
var string = ""
|
||||||
@ -85,6 +80,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Traverses each digitbox to retrieve the held value.
|
||||||
public override var text: String? {
|
public override var text: String? {
|
||||||
get {
|
get {
|
||||||
var string = ""
|
var string = ""
|
||||||
@ -107,34 +103,48 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override var title: String? {
|
/// Updates the visual appearance of the container, with some logical laterations as well.
|
||||||
get { return titleLabel.text }
|
public override func updateUI(appearance: Appearance) {
|
||||||
set {
|
|
||||||
if let formText = newValue, !formText.isEmpty {
|
self.appearance = appearance
|
||||||
titleContainerDistance?.constant = 10
|
isUserInteractionEnabled = true
|
||||||
} else {
|
titleLabel.textColor = .mfBattleshipGrey()
|
||||||
titleContainerDistance?.constant = 0
|
hideBorder = false
|
||||||
|
feedback = showError ? errorMessage : nil
|
||||||
|
|
||||||
|
switch appearance {
|
||||||
|
case .original:
|
||||||
|
digitFields.forEach {
|
||||||
|
$0.borderStrokeColor = .mfSilver()
|
||||||
|
$0.bottomBar.backgroundColor = UIColor.black.cgColor
|
||||||
}
|
}
|
||||||
|
case .error:
|
||||||
super.title = newValue
|
digitFields.forEach {
|
||||||
}
|
$0.borderStrokeColor = .mfPumpkin()
|
||||||
}
|
$0.bottomBar.backgroundColor = UIColor.mfPumpkin().cgColor
|
||||||
|
|
||||||
public override var errorMessage: String? {
|
|
||||||
didSet {
|
|
||||||
if let errorMessage = errorMessage, !errorMessage.isEmpty {
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
|
|
||||||
if self.showError {
|
|
||||||
self.feedbackContainerDistance?.constant = 10
|
|
||||||
self.setNeedsLayout()
|
|
||||||
}
|
|
||||||
|
|
||||||
self.digitFields.forEach { $0.showErrorState(true) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.digitFields.forEach { $0.showErrorState(true) }
|
||||||
|
case .lock:
|
||||||
|
digitFields.forEach {
|
||||||
|
$0.isUserInteractionEnabled = false
|
||||||
|
$0.hideBorder = true
|
||||||
|
$0.bottomBar.backgroundColor = UIColor.clear.cgColor
|
||||||
|
}
|
||||||
|
case .select:
|
||||||
|
digitFields.forEach {
|
||||||
|
$0.borderStrokeColor = .black
|
||||||
|
$0.bottomBar.backgroundColor = UIColor.black.cgColor
|
||||||
|
}
|
||||||
|
case .disable:
|
||||||
|
digitFields.forEach {
|
||||||
|
$0.isUserInteractionEnabled = false
|
||||||
|
$0.borderStrokeColor = .mfSilver()
|
||||||
|
$0.bottomBar.backgroundColor = self.isEnabled ? UIColor.black.cgColor : UIColor.mfSilver().cgColor
|
||||||
|
}
|
||||||
|
titleLabel.textColor = self.isEnabled ? .mfBattleshipGrey() : .mfSilver()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshBorderUI(bottomBarSize: appearance == .error ? 4 : 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -158,7 +168,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
public init(numberOfDigits: Int, bothDelegates delegate: (UITextFieldDelegate & TextFieldDelegate)?, size: CGFloat? = nil) {
|
public init(numberOfDigits: Int, bothDelegates delegate: (UITextFieldDelegate & TextFieldDelegate)?, size: CGFloat? = nil) {
|
||||||
super.init(bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate))
|
super.init(bothDelegates: delegate)
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
self.numberOfDigits = numberOfDigits
|
self.numberOfDigits = numberOfDigits
|
||||||
@ -176,52 +186,18 @@ import UIKit
|
|||||||
|
|
||||||
open func setup() {
|
open func setup() {
|
||||||
|
|
||||||
|
// Border for Field Container will not be shown.
|
||||||
hideBorder = true
|
hideBorder = true
|
||||||
// titleLabel.styleB2(true)
|
|
||||||
alignCenterHorizontal()
|
alignCenterHorizontal()
|
||||||
|
isAccessibilityElement = false
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func setupFieldContainerContent(_ container: UIView) {
|
open override func setupFieldContainerContent(_ container: UIView) {
|
||||||
|
|
||||||
|
textField.removeFromSuperview()
|
||||||
setupTextFieldsView(forSize: CGFloat(numberOfDigits))
|
setupTextFieldsView(forSize: CGFloat(numberOfDigits))
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Lifecycle
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
open override func updateView(_ size: CGFloat) {
|
|
||||||
super.updateView(size)
|
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
|
|
||||||
self.titleLabel.updateView(size)
|
|
||||||
|
|
||||||
if !self.digitFields.isEmpty {
|
|
||||||
|
|
||||||
StackableViewController.remove(self.digitFields)
|
|
||||||
|
|
||||||
self.digitFields.forEach { $0.updateView(size) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Layout text boxes.
|
|
||||||
self.setupTextFieldsView(forSize: size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// 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 {
|
func createDigitField() -> DigitBox {
|
||||||
|
|
||||||
let textField = DigitBox()
|
let textField = DigitBox()
|
||||||
@ -237,7 +213,7 @@ import UIKit
|
|||||||
|
|
||||||
// Remove all current UI.
|
// Remove all current UI.
|
||||||
if !digitFields.isEmpty {
|
if !digitFields.isEmpty {
|
||||||
StackableViewController.remove(digitFields)
|
digitFieldsStack?.subviews.forEach { $0.removeFromSuperview() }
|
||||||
}
|
}
|
||||||
|
|
||||||
if numberOfDigits > 0 {
|
if numberOfDigits > 0 {
|
||||||
@ -258,6 +234,42 @@ import UIKit
|
|||||||
accessibilityElements = accessibleElements + [feedbackLabel]
|
accessibilityElements = accessibleElements + [feedbackLabel]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.titleLabel.updateView(size)
|
||||||
|
|
||||||
|
if !self.digitFields.isEmpty {
|
||||||
|
|
||||||
|
self.digitFieldsStack?.subviews.forEach { $0.removeFromSuperview() }
|
||||||
|
self.digitFields.forEach { $0.updateView(size) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout text boxes.
|
||||||
|
self.setupTextFieldsView(forSize: size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
func removeError() {
|
||||||
|
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.digitFields.forEach { $0.showErrorState(false) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func valueChanged() {
|
override func valueChanged() {
|
||||||
super.valueChanged()
|
super.valueChanged()
|
||||||
|
|
||||||
@ -289,27 +301,13 @@ import UIKit
|
|||||||
|
|
||||||
func setupTextFieldsView(forSize size: CGFloat) {
|
func setupTextFieldsView(forSize size: CGFloat) {
|
||||||
|
|
||||||
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(),
|
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize() else { return }
|
||||||
let digitFieldsView = digitFieldsView
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
StackableViewController.populateViewHorizontally(digitFieldsView, withUIArray: digitFields, withSpacingBlock: { object in
|
let stack = UIStackView(arrangedSubviews: digitFields)
|
||||||
|
self.digitFieldsStack = stack
|
||||||
var inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space)
|
textField.addSubview(stack)
|
||||||
|
stack.distribution = .equalSpacing
|
||||||
if self.digitFields.count == 1 {
|
stack.spacing = space
|
||||||
inset.left = 0
|
|
||||||
inset.right = 0
|
|
||||||
|
|
||||||
} else if let field = object as? UITextField, field == self.digitFields.first {
|
|
||||||
inset.left = 0
|
|
||||||
|
|
||||||
} else if let field = object as? UITextField, field == self.digitFields.last {
|
|
||||||
inset.right = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return inset
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func defaultValidationBlock() {
|
public override func defaultValidationBlock() {
|
||||||
@ -367,6 +365,7 @@ import UIKit
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
guard let dictionary = json else { return }
|
guard let dictionary = json else { return }
|
||||||
|
|
||||||
@ -382,25 +381,12 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
|
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
|
||||||
|
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open override class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
open override class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
return 44
|
return 44
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Accessibility
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
open override class func accessibilityElements() -> [Any]? {
|
|
||||||
// let fields = []
|
|
||||||
|
|
||||||
// return self.digitFields
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Text Field Delegate
|
// MARK: - Text Field Delegate
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -73,7 +73,7 @@ import UIKit
|
|||||||
return layer
|
return layer
|
||||||
}()
|
}()
|
||||||
|
|
||||||
public private(set) var appearance: Appearance = .original
|
public var appearance: Appearance = .original
|
||||||
|
|
||||||
public var showError = false
|
public var showError = false
|
||||||
|
|
||||||
|
|||||||
@ -160,6 +160,7 @@
|
|||||||
strokeColor = .black
|
strokeColor = .black
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensure you have defined a CaretSize with Orientation before calling.
|
||||||
@objc public func setConstraints() {
|
@objc public func setConstraints() {
|
||||||
|
|
||||||
guard let dimensions = size?.dimensions() else { return }
|
guard let dimensions = size?.dimensions() else { return }
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import UIKit
|
|||||||
// For separation between cells.
|
// For separation between cells.
|
||||||
public var topSeparatorView: SeparatorView?
|
public var topSeparatorView: SeparatorView?
|
||||||
public var bottomSeparatorView: SeparatorView?
|
public var bottomSeparatorView: SeparatorView?
|
||||||
|
|
||||||
public enum SeparatorFrequency: String {
|
public enum SeparatorFrequency: String {
|
||||||
case all
|
case all
|
||||||
case allExceptTop
|
case allExceptTop
|
||||||
@ -40,17 +41,21 @@ import UIKit
|
|||||||
|
|
||||||
// MARK: - Styling
|
// MARK: - Styling
|
||||||
open func style(with styleString: String?) {
|
open func style(with styleString: String?) {
|
||||||
guard let styleString = styleString else {
|
|
||||||
return
|
guard let styleString = styleString else { return }
|
||||||
}
|
|
||||||
switch styleString {
|
switch styleString {
|
||||||
case "standard":
|
case "standard":
|
||||||
styleStandard()
|
styleStandard()
|
||||||
|
|
||||||
case "header":
|
case "header":
|
||||||
styleHeader()
|
styleHeader()
|
||||||
|
|
||||||
case "none":
|
case "none":
|
||||||
styleNone()
|
styleNone()
|
||||||
default: break
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,13 +209,18 @@ import UIKit
|
|||||||
// MARK: - Arrow
|
// MARK: - Arrow
|
||||||
/// Adds the standard mvm style caret to the accessory view
|
/// Adds the standard mvm style caret to the accessory view
|
||||||
@objc public func addCaretViewAccessory() {
|
@objc public func addCaretViewAccessory() {
|
||||||
|
|
||||||
guard accessoryView == nil else { return }
|
guard accessoryView == nil else { return }
|
||||||
let width: CGFloat = 6
|
|
||||||
let height: CGFloat = 10
|
|
||||||
caretView = CaretView(lineWidth: 1)
|
caretView = CaretView(lineWidth: 1)
|
||||||
caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
caretView?.size = .small(.vertical)
|
||||||
caretViewWidthSizeObject = MFSizeObject(standardSize: width, standardiPadPortraitSize: 9)
|
caretView?.setConstraints()
|
||||||
caretViewHeightSizeObject = MFSizeObject(standardSize: height, standardiPadPortraitSize: 16)
|
|
||||||
|
if let size = caretView?.size?.dimensions() {
|
||||||
|
caretViewWidthSizeObject = MFSizeObject(standardSize: size.width, standardiPadPortraitSize: 9)
|
||||||
|
caretViewHeightSizeObject = MFSizeObject(standardSize: size.height, standardiPadPortraitSize: 16)
|
||||||
|
}
|
||||||
|
|
||||||
accessoryView = caretView
|
accessoryView = caretView
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +268,7 @@ import UIKit
|
|||||||
} else {
|
} else {
|
||||||
topSeparatorView?.hide()
|
topSeparatorView?.hide()
|
||||||
bottomSeparatorView?.setAsLight()
|
bottomSeparatorView?.setAsLight()
|
||||||
setSeparatorFrequency(TableViewCell.SeparatorFrequency.allExceptTop, indexPath: indexPath)
|
setSeparatorFrequency(.allExceptTop, indexPath: indexPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user