From a632031d4147dec293dc110ebc2c720522ce8613 Mon Sep 17 00:00:00 2001 From: Anton Kochetkov Date: Wed, 6 Mar 2024 16:01:17 +0300 Subject: [PATCH 1/3] added required field designation --- .../Source/FloatingLabelTextField.swift | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/AGInputControls/Source/FloatingLabelTextField.swift b/AGInputControls/Source/FloatingLabelTextField.swift index 0e3b764..0db12c0 100644 --- a/AGInputControls/Source/FloatingLabelTextField.swift +++ b/AGInputControls/Source/FloatingLabelTextField.swift @@ -82,6 +82,24 @@ open class FloatingLabelTextField : FormattingTextField { } } + open var isRequired: Bool = false { + didSet { + configureColors() + } + } + + open var requiredText: String? = " *" { + didSet { + configureColors() + } + } + + open var requiredTextColor: UIColor = .red { + didSet { + configureColors() + } + } + /// Colors placeholder label, bottom label and underline view in `tintColor` when textfield is focused. Default is `true` open var highlightsWhenActive = true @@ -211,8 +229,20 @@ open class FloatingLabelTextField : FormattingTextField { } private func configurePlaceholder() { - guard placeholder != nil else { return } - placeholderLabel.text = placeholder + guard let placeholder else { return } + if isRequired, let requiredText { + placeholderLabel.text = nil + let placeholderWithRequiredText = placeholder + requiredText + let mutableAttributedString = NSMutableAttributedString( + string: placeholderWithRequiredText, + attributes: [.foregroundColor: placeholderLabel.textColor]) + let range = (placeholderWithRequiredText as NSString).range(of: requiredText) + mutableAttributedString.addAttribute(.foregroundColor, value: requiredTextColor, range: range) + placeholderLabel.attributedText = mutableAttributedString + } else { + placeholderLabel.attributedText = nil + placeholderLabel.text = placeholder + } placeholderLabel.sizeToFit() } @@ -232,6 +262,7 @@ open class FloatingLabelTextField : FormattingTextField { } placeholderLabel.textColor = color + configurePlaceholder() underlineView.backgroundColor = color bottomLabel.textColor = color } From 8a1694d199b6b62aa2672380c3d368c62c748616 Mon Sep 17 00:00:00 2001 From: Anton Kochetkov Date: Wed, 6 Mar 2024 16:01:40 +0300 Subject: [PATCH 2/3] fix show without required placeholder and added example --- Examples/FloatingLabelViewController.swift | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Examples/FloatingLabelViewController.swift b/Examples/FloatingLabelViewController.swift index 308cf57..61b4f76 100644 --- a/Examples/FloatingLabelViewController.swift +++ b/Examples/FloatingLabelViewController.swift @@ -25,6 +25,9 @@ class StackViewController: UIViewController { stackView.axis = .vertical stackView.spacing = 1 + let endEditingTap = UITapGestureRecognizer(target: self, action: #selector(tapView)) + view.addGestureRecognizer(endEditingTap) + NSLayoutConstraint.activate([ stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16), stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16), @@ -41,6 +44,10 @@ class StackViewController: UIViewController { // stackView.alignment = .leading // } + @objc private func tapView() { + view.endEditing(true) + } + final class Entry: UIView { let title: String @@ -96,6 +103,7 @@ final class FloatingLabelViewController: StackViewController { let floatTextField = FloatingLabelTextField() let floatingFieldNoFormatting = FloatingLabelTextField() + let floatingFieldNoFormattingWithRequired = FloatingLabelTextField() let floatingPhoneTextField = FloatingLabelTextField() override func viewDidLoad() { @@ -120,6 +128,15 @@ final class FloatingLabelViewController: StackViewController { floatingFieldNoFormatting.leftView?.tintColor = .lightGray floatingFieldNoFormatting.leftViewMode = .always + floatingFieldNoFormattingWithRequired.backgroundColor = UIColor.systemGreen.withAlphaComponent(0.15) + floatingFieldNoFormattingWithRequired.bottomText = "Bottom text" + floatingFieldNoFormattingWithRequired.placeholder = "Floating placeholder" + floatingFieldNoFormattingWithRequired.isRequired = true + floatingFieldNoFormattingWithRequired.showUnderlineView = true + floatingFieldNoFormattingWithRequired.highlightsWhenActive = true + floatingFieldNoFormattingWithRequired.clearButtonMode = .whileEditing + floatingFieldNoFormattingWithRequired.addTarget(self, action: #selector(didChangeNoFormattingWithRequired), for: .editingChanged) + floatTextField.placeholder = "Card number" floatTextField.tintColor = .systemPurple floatTextField.backgroundColor = .white @@ -141,6 +158,8 @@ final class FloatingLabelViewController: StackViewController { stackView.addArrangedSubview(Entry(title: "No formatting", targetView: floatingFieldNoFormatting)) + stackView.addArrangedSubview(Entry(title: "No formatting with required", targetView: floatingFieldNoFormattingWithRequired)) + stackView.addArrangedSubview(Entry(title: "Regular formatting", targetView: floatTextField)) stackView.addArrangedSubview(Entry(title: "Phone floating textfield", targetView: floatingPhoneTextField)) @@ -154,6 +173,11 @@ final class FloatingLabelViewController: StackViewController { tf.isError = isError } + @objc private func didChangeNoFormattingWithRequired(textField: UITextField) { + guard let tf = textField as? FloatingLabelTextField else { return } + tf.isError = tf.text!.count > 5 + } + @objc func didTapClear() { floatingFieldNoFormatting.text = nil } From f3aca742ee579fef3b28532ea769076c40b8dbf2 Mon Sep 17 00:00:00 2001 From: Anton Kochetkov Date: Tue, 9 Apr 2024 20:18:54 +0300 Subject: [PATCH 3/3] properties of the required field have been changed and a mention has been added to the readme --- .../Source/FloatingLabelTextField.swift | 21 ++++++------------- README.md | 1 + 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/AGInputControls/Source/FloatingLabelTextField.swift b/AGInputControls/Source/FloatingLabelTextField.swift index 0db12c0..cfc52c5 100644 --- a/AGInputControls/Source/FloatingLabelTextField.swift +++ b/AGInputControls/Source/FloatingLabelTextField.swift @@ -82,19 +82,8 @@ open class FloatingLabelTextField : FormattingTextField { } } - open var isRequired: Bool = false { - didSet { - configureColors() - } - } - - open var requiredText: String? = " *" { - didSet { - configureColors() - } - } - - open var requiredTextColor: UIColor = .red { + /// shows in the placeholder the designation of a required field using " \*" with a color from errorColor. Default is `false` + public var isRequired: Bool = false { didSet { configureColors() } @@ -161,6 +150,8 @@ open class FloatingLabelTextField : FormattingTextField { textPadding.top + (font!.lineHeight * floatingLabelScaleFactor + floatingLabelBottomPadding) } + private let requiredText: String = " *" + //MARK: - Init required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) @@ -230,14 +221,14 @@ open class FloatingLabelTextField : FormattingTextField { private func configurePlaceholder() { guard let placeholder else { return } - if isRequired, let requiredText { + if isRequired { placeholderLabel.text = nil let placeholderWithRequiredText = placeholder + requiredText let mutableAttributedString = NSMutableAttributedString( string: placeholderWithRequiredText, attributes: [.foregroundColor: placeholderLabel.textColor]) let range = (placeholderWithRequiredText as NSString).range(of: requiredText) - mutableAttributedString.addAttribute(.foregroundColor, value: requiredTextColor, range: range) + mutableAttributedString.addAttribute(.foregroundColor, value: errorTintColor, range: range) placeholderLabel.attributedText = mutableAttributedString } else { placeholderLabel.attributedText = nil diff --git a/README.md b/README.md index 391405e..40c294e 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ FloatingLabelTextField is a `UITextField` subclass which resembles [Material des floatTextField.formattingMask = "##/##" // Formatting mask floatTextField.placeholder = "Expires at" floatTextField.textPaddings = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0) // Paddings for text and floating placeholder + floatTextField.isRequired = true // Placeholder displays the required field symbol floatTextField.highlightsWhenActive = true // Placeholder and underline view and bottom label are filled by tintColor when textfield is active floatTextField.errorTintColor = .systemRed