Skip to content

Instantly share code, notes, and snippets.

@leehericks
Last active February 9, 2019 14:30
Show Gist options
  • Save leehericks/f2ed93e6117ed847f4487f77f42189e8 to your computer and use it in GitHub Desktop.
Save leehericks/f2ed93e6117ed847f4487f77f42189e8 to your computer and use it in GitHub Desktop.
A UITextField subclass written in Swift with manual, block and delegate APIs for evaluating text validity and enabling or disabling the keyboard return key.
//
// ValidatedTextField.swift
//
// Created by Lee Hericks on 2019/02/08.
//
import UIKit
/**
A protocol for delegating the task of determining validation for `ValidatedTextField`.
*/
@objc public protocol ValidatedTextFieldDelegate: NSObjectProtocol {
/**
Asks the delegate to determine the validation of the given text, setting the result to the hasValidText property.
- Parameter textField: The textfield whose text needs validation.
- Parameter text: The text to validate.
*/
@objc optional func textField(_ textField: ValidatedTextField, validityOf text: String) -> Bool
/**
Informs the delegate when the validity of the text has changed.
- Parameter textField: The textfield whose text validty has changed.
- Parameter isValid: The new validity of the text.
*/
@objc optional func textField(_ textField: ValidatedTextField, didChangeValidity isValid: Bool) -> Void
}
public final class ValidatedTextField: UITextField {
// MARK: - Getting and Setting Validity
/**
Tells whether or not the text in the text field is valid. It can be set manually,
or will be automatically set to the result of the validation block or validation delegate result.
*/
public var hasValidText = false {
didSet {
self.validityDidChange?(hasValidText)
self.validationDelegate?.textField?(self, didChangeValidity: hasValidText)
}
}
// MARK: - Using Validation Blocks
/**
A block returns whether or not the given text is valid.
If this block is set, it is used instead of the delegate to determine validity.
If neither the validation block nor the validation delegate have been set,
validity must be changed manually by setting `hasValidText` directly to enable or disable the return key.
*/
public var validation: ((String) -> Bool)?
/**
A block which is called when the validity of the text field has changed.
*/
public var validityDidChange: ((Bool) -> Void)?
// MARK: - Using the Validation Delegate
/**
A delegate conforming to `ValidatedTextFieldDelegate` which optionally evaluates validity
and receives notification when validity has changed.
If the validation block nor the validation delegate have been set,
validity must be changed manually by setting `hasValidText`.
*/
@IBOutlet public weak var validationDelegate: ValidatedTextFieldDelegate?
// MARK: - Required Initialization
override init(frame: CGRect) {
super.init(frame: frame)
self.initializeRequiredKeyboardSettings()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initializeRequiredKeyboardSettings()
}
/**
Initializes input settings for enabling return key when text is deemed valid.
*/
private func initializeRequiredKeyboardSettings() {
// Required for return key enabled state to change via return value of hasText.
self.enablesReturnKeyAutomatically = true
// Default behavior, changing returnKeyType will not affect return key enabling functionality.
self.returnKeyType = .done
}
// MARK: - Overriding hasText to affect the return key state
/**
When the UITextField `enablesReturnKeyAutomatically` property is set to `true`,
the keyboard return key is enabled when this property returns `true`.
By overriding this property and implementing a concept of validity for the text field,
we can enable the keyboard whenever the text is deemed valid.
*/
override public var hasText: Bool {
guard let text = self.text else {
return false
}
if let validate = self.validation {
hasValidText = validate(text)
}
else if let validationDelegate = self.validationDelegate, validationDelegate.responds(to: #selector(ValidatedTextFieldDelegate.textField(_:validityOf:))) {
hasValidText = validationDelegate.textField!(self, validityOf: text)
}
return hasValidText
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment