I'd like to create Eureka row to look and behave as Postal Address Row in create/edit Contact Screen in iOS Contacts App. I need to present Label or Country Picker when corresponding button in cell is pressed. Based on Eureka documentation:
every row that displays a new view controller must conform to PresenterRowType protocol
However this protocol is generic. So my understanding is that I can't show more than one child screen per row. Do I get this right? Is it possible to present more than one child screen?
What I have so far follows.
Row Protocols:
protocol PostalAddressFormatterConformance: class {
var streetUseFormatterDuringInput: Bool { get set }
var streetFormatter: Formatter? { get set }
var stateUseFormatterDuringInput: Bool { get set }
var stateFormatter: Formatter? { get set }
var postalCodeUseFormatterDuringInput: Bool { get set }
var postalCodeFormatter: Formatter? { get set }
var cityUseFormatterDuringInput: Bool { get set }
var cityFormatter: Formatter? { get set }
}
protocol LabeledRowConformance {
func onLabelButtonDidPress()
}
protocol CountryRowConformance {
func onCountryButtonDidPress()
}
protocol PostalAddressRowConformance: PostalAddressFormatterConformance, LabeledRowConformance, CountryRowConformance {
var placeholderColor : UIColor? { get set }
var streetPlaceholder : String? { get set }
var statePlaceholder : String? { get set }
var postalCodePlaceholder : String? { get set }
var cityPlaceholder : String? { get set }
}
Postal Address Row Base class:
class _PostalAddressRow<Cell: CellType>: Row<Cell>, PostalAddressRowConformance, CountryRowConformance, LabeledRowConformance, KeyboardReturnHandler where Cell: BaseCell, Cell: PostalAddressCellConformance {
//MARK: - LabeledRowConformance
func onLabelButtonDidPress() {
// TODO: Present Label Picker Screen
}
//MARK: - CountryRowConformance
func onCountryButtonDidPress() {
// TODO: Present Country Picker Screen
}
//MARK: - KeyboardReturnHandler
/// Configuration for the keyboardReturnType of this row
var keyboardReturnType : KeyboardReturnTypeConfiguration?
//MARK: - PostalAddressRowConformance
/// The textColor for the textField's placeholder
var placeholderColor : UIColor?
/// The placeholder for the street textField
var streetPlaceholder : String?
/// The placeholder for the state textField
var statePlaceholder : String?
/// The placeholder for the zip textField
var postalCodePlaceholder : String?
/// The placeholder for the city textField
var cityPlaceholder : String?
/// A formatter to be used to format the user's input for street
var streetFormatter: Formatter?
/// A formatter to be used to format the user's input for state
var stateFormatter: Formatter?
/// A formatter to be used to format the user's input for zip
var postalCodeFormatter: Formatter?
/// A formatter to be used to format the user's input for city
var cityFormatter: Formatter?
/// If the formatter should be used while the user is editing the street.
var streetUseFormatterDuringInput: Bool
/// If the formatter should be used while the user is editing the state.
var stateUseFormatterDuringInput: Bool
/// If the formatter should be used while the user is editing the zip.
var postalCodeUseFormatterDuringInput: Bool
/// If the formatter should be used while the user is editing the city.
var cityUseFormatterDuringInput: Bool
public required init(tag: String?) {
streetUseFormatterDuringInput = false
stateUseFormatterDuringInput = false
postalCodeUseFormatterDuringInput = false
cityUseFormatterDuringInput = false
super.init(tag: tag)
}
}
Postal Address Row Final:
final class PostalAddressRow: _PostalAddressRow<PostalAddressCell>, RowType {
public required init(tag: String? = nil) {
super.init(tag: tag)
// TODO
cellProvider = CellProvider<PostalAddressCell>(nibName: "PostalAddressCell")
}
}
Cell:
public protocol CountryCellConformance {
var countryButton: UIButton? { get }
}
public protocol PostalAddressCellConformance: CountryCellConformance {
var streetTextField: UITextField? { get }
var stateTextField: UITextField? { get }
var postalCodeTextField: UITextField? { get }
var cityTextField: UITextField? { get }
}
class _PostalAddressCell<T: PostalAddressType>: Cell<T>, PostalAddressCellConformance, UITextFieldDelegate, CellType {
#IBOutlet weak var changeLabelButton: UIButton!
//MARK: - CountryCellConformance
#IBOutlet weak var countryButton: UIButton?
//MARK: - PostalAddressCellConformance
#IBOutlet weak var streetTextField: UITextField?
#IBOutlet weak var stateTextField: UITextField?
#IBOutlet weak var postalCodeTextField: UITextField?
#IBOutlet weak var cityTextField: UITextField?
// ??? Style Color
#IBOutlet var separatorViews: [UIView]!
// Helper
var textFieldOrdering: [UITextField?] = []
//MARK: - Lifecycle
public required init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
open override func awakeFromNib() {
super.awakeFromNib()
textFieldOrdering = [streetTextField, stateTextField, postalCodeTextField, cityTextField]
}
deinit {
streetTextField?.delegate = nil
streetTextField?.removeTarget(self, action: nil, for: .allEvents)
stateTextField?.delegate = nil
stateTextField?.removeTarget(self, action: nil, for: .allEvents)
postalCodeTextField?.delegate = nil
postalCodeTextField?.removeTarget(self, action: nil, for: .allEvents)
cityTextField?.delegate = nil
cityTextField?.removeTarget(self, action: nil, for: .allEvents)
}
//MARK: - Actions
#IBAction func changeLabelButtonPressed(_ sender: Any) {
if let rowConformance = row as? LabeledRowConformance {
rowConformance.onLabelButtonDidPress()
}
}
#IBAction func countryButtonPressed(_ sender: Any) {
if let rowConformance = row as? CountryRowConformance {
rowConformance.onCountryButtonDidPress()
}
}
func internalNavigationAction(_ sender: UIBarButtonItem) {
guard let inputAccesoryView = inputAccessoryView as? NavigationAccessoryView else { return }
var index = 0
for field in textFieldOrdering {
if field?.isFirstResponder == true {
let _ = sender == inputAccesoryView.previousButton ? textFieldOrdering[index-1]?.becomeFirstResponder() : textFieldOrdering[index+1]?.becomeFirstResponder()
break
}
index += 1
}
}
func textFieldDidChange(_ textField : UITextField){
if row.baseValue == nil{
row.baseValue = PostalAddress()
}
guard let textValue = textField.text else {
switch(textField) {
case let field where field == streetTextField:
row.value?.street = nil
case let field where field == stateTextField:
row.value?.state = nil
case let field where field == postalCodeTextField:
row.value?.postalCode = nil
case let field where field == cityTextField:
row.value?.city = nil
default:
break
}
return
}
if let rowConformance = row as? PostalAddressRowConformance {
var useFormatterDuringInput = false
var valueFormatter: Formatter?
switch(textField) {
case let field where field == streetTextField:
useFormatterDuringInput = rowConformance.streetUseFormatterDuringInput
valueFormatter = rowConformance.streetFormatter
case let field where field == stateTextField:
useFormatterDuringInput = rowConformance.stateUseFormatterDuringInput
valueFormatter = rowConformance.stateFormatter
case let field where field == postalCodeTextField:
useFormatterDuringInput = rowConformance.postalCodeUseFormatterDuringInput
valueFormatter = rowConformance.postalCodeFormatter
case let field where field == cityTextField:
useFormatterDuringInput = rowConformance.cityUseFormatterDuringInput
valueFormatter = rowConformance.cityFormatter
default:
break
}
if let formatter = valueFormatter, useFormatterDuringInput{
let value: AutoreleasingUnsafeMutablePointer<AnyObject?> = AutoreleasingUnsafeMutablePointer<AnyObject?>.init(UnsafeMutablePointer<T>.allocate(capacity: 1))
let errorDesc: AutoreleasingUnsafeMutablePointer<NSString?>? = nil
if formatter.getObjectValue(value, for: textValue, errorDescription: errorDesc) {
switch(textField){
case let field where field == streetTextField:
row.value?.street = value.pointee as? String
case let field where field == stateTextField:
row.value?.state = value.pointee as? String
case let field where field == postalCodeTextField:
row.value?.postalCode = value.pointee as? String
case let field where field == cityTextField:
row.value?.city = value.pointee as? String
default:
break
}
if var selStartPos = textField.selectedTextRange?.start {
let oldVal = textField.text
textField.text = row.displayValueFor?(row.value)
if let f = formatter as? FormatterProtocol {
selStartPos = f.getNewPosition(forPosition: selStartPos, inTextInput: textField, oldValue: oldVal, newValue: textField.text)
}
textField.selectedTextRange = textField.textRange(from: selStartPos, to: selStartPos)
}
return
}
}
}
guard !textValue.isEmpty else {
switch(textField){
case let field where field == streetTextField:
row.value?.street = nil
case let field where field == stateTextField:
row.value?.state = nil
case let field where field == postalCodeTextField:
row.value?.postalCode = nil
case let field where field == cityTextField:
row.value?.city = nil
default:
break
}
return
}
switch(textField){
case let field where field == streetTextField:
row.value?.street = textValue
case let field where field == stateTextField:
row.value?.state = textValue
case let field where field == postalCodeTextField:
row.value?.postalCode = textValue
case let field where field == cityTextField:
row.value?.city = textValue
default:
break
}
}
//MARK: - Setup
override func setup() {
super.setup()
height = { 149 }
selectionStyle = .none
for textField in textFieldOrdering {
textField?.addTarget(self,
action: #selector(_PostalAddressCell.textFieldDidChange(_:)), // TODO: Move in extension
for: .editingChanged)
textField?.textAlignment = .left
textField?.clearButtonMode = .whileEditing
textField?.delegate = self
textField?.font = .preferredFont(forTextStyle: .body)
}
for separator in separatorViews {
separator.backgroundColor = .gray
}
}
//MARK: - Update
override func update() {
super.update()
textLabel?.text = nil
detailTextLabel?.text = nil
imageView?.image = nil
for textField in textFieldOrdering {
textField?.isEnabled = !row.isDisabled
textField?.textColor = row.isDisabled ? .gray : .black
textField?.autocorrectionType = .no
textField?.autocapitalizationType = .words
}
streetTextField?.text = row.value?.street
streetTextField?.keyboardType = .asciiCapable
stateTextField?.text = row.value?.state
stateTextField?.keyboardType = .asciiCapable
postalCodeTextField?.text = row.value?.postalCode
postalCodeTextField?.keyboardType = .numbersAndPunctuation
cityTextField?.text = row.value?.city
cityTextField?.keyboardType = .asciiCapable
if let rowConformance = row as? PostalAddressRowConformance {
setPlaceholderToTextField(textField: streetTextField, placeholder: rowConformance.streetPlaceholder)
setPlaceholderToTextField(textField: stateTextField, placeholder: rowConformance.statePlaceholder)
setPlaceholderToTextField(textField: postalCodeTextField, placeholder: rowConformance.postalCodePlaceholder)
setPlaceholderToTextField(textField: cityTextField, placeholder: rowConformance.cityPlaceholder)
}
countryButton?.setTitle(String(describing: row.value?.country), for: .normal)
}
//MARK: - BaseCell Responder
override func cellCanBecomeFirstResponder() -> Bool {
return !row.isDisabled && (
streetTextField?.canBecomeFirstResponder == true ||
stateTextField?.canBecomeFirstResponder == true ||
postalCodeTextField?.canBecomeFirstResponder == true ||
cityTextField?.canBecomeFirstResponder == true
)
}
override func cellBecomeFirstResponder(withDirection direction: Direction) -> Bool {
return direction == .down ? textFieldOrdering.first??.becomeFirstResponder() ?? false : textFieldOrdering.last??.becomeFirstResponder() ?? false
}
override func cellResignFirstResponder() -> Bool {
return streetTextField?.resignFirstResponder() ?? true
&& stateTextField?.resignFirstResponder() ?? true
&& postalCodeTextField?.resignFirstResponder() ?? true
&& stateTextField?.resignFirstResponder() ?? true
&& cityTextField?.resignFirstResponder() ?? true
}
override var inputAccessoryView: UIView? {
if let v = formViewController()?.inputAccessoryView(for: row) as? NavigationAccessoryView {
guard let first = textFieldOrdering.first, let last = textFieldOrdering.last, first != last else { return v }
if first?.isFirstResponder == true {
v.nextButton.isEnabled = true
v.nextButton.target = self
v.nextButton.action = #selector(_PostalAddressCell.internalNavigationAction(_:)) // TODO: Move in extension
} else if last?.isFirstResponder == true {
v.previousButton.target = self
v.previousButton.action = #selector(_PostalAddressCell.internalNavigationAction(_:))
v.previousButton.isEnabled = true
} else {
v.previousButton.target = self
v.previousButton.action = #selector(_PostalAddressCell.internalNavigationAction(_:))
v.nextButton.target = self
v.nextButton.action = #selector(_PostalAddressCell.internalNavigationAction(_:))
v.previousButton.isEnabled = true
v.nextButton.isEnabled = true
}
return v
}
return super.inputAccessoryView
}
//MARK: - UITextFieldDelegate
func textFieldDidBeginEditing(_ textField: UITextField) {
formViewController()?.beginEditing(of: self)
formViewController()?.textInputDidBeginEditing(textField, cell: self)
}
func textFieldDidEndEditing(_ textField: UITextField) {
formViewController()?.endEditing(of: self)
formViewController()?.textInputDidEndEditing(textField, cell: self)
textFieldDidChange(textField)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return formViewController()?.textInputShouldReturn(textField, cell: self) ?? true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return formViewController()?.textInputShouldEndEditing(textField, cell: self) ?? true
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return formViewController()?.textInputShouldBeginEditing(textField, cell: self) ?? true
}
func textFieldShouldClear(_ textField: UITextField) -> Bool {
return formViewController()?.textInputShouldClear(textField, cell: self) ?? true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
return formViewController()?.textInputShouldEndEditing(textField, cell: self) ?? true
}
//MARK: - Private
private func setPlaceholderToTextField(textField: UITextField?, placeholder: String?) {
if let placeholder = placeholder, let textField = textField {
if let color = (row as? PostalAddressRowConformance)?.placeholderColor {
textField.attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSForegroundColorAttributeName: color])
} else {
textField.placeholder = placeholder
}
}
}
}
final class PostalAddressCell: _PostalAddressCell<PostalAddress> {
public required init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Models:
protocol CountryType: Equatable {
var country: Country? { get set }
}
func == <T: CountryType>(lhs: T, rhs: T) -> Bool {
return lhs.country == rhs.country
}
//
protocol PostalAddressType: CountryType {
var street: String? { get set }
var state: String? { get set }
var postalCode: String? { get set }
var city: String? { get set }
}
func == <T: PostalAddressType>(lhs: T, rhs: T) -> Bool {
return lhs.street == rhs.street && lhs.state == rhs.state && lhs.postalCode == rhs.postalCode && lhs.city == rhs.city && lhs.country == rhs.country
}
//
class PostalAddress: PostalAddressType {
var street: String?
var state: String?
var postalCode: String?
var city: String?
var country: Country?
public init() {}
public init(street: String?, state: String?, postalCode: String?, city: String?, country: Country?) {
self.street = street
self.state = state
self.postalCode = postalCode
self.city = city
self.country = country
}
}
Related
I have problem with associating the textField to my shouldChangeCharactersIn func, and this textField should contain Int values. First textField should contain String value, and second should contain Int value. Confirm button should be enabled only if textFields are filled with correct types. That's my app:
And code:
import UIKit
class LoginViewController: UIViewController, UITextFieldDelegate {
var av = ActualValues()
var statsVC = StatsViewController()
var closureBlock: (() -> Void)?
#IBOutlet weak var idTextField: UITextField!
#IBOutlet weak var idCheckButton: UIButton!
#IBOutlet weak var segmentedControl: UISegmentedControl!
#IBOutlet weak var targetsTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
statsVC.allRunsFunc()
idTextField.delegate = self
idCheckButton.isEnabled = false
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
av.shift = 1
allRunsFunc()
}
#IBAction func idCheckButtonDidPress(_ sender: UIButton) {
av.id = idTextField.text!
av.databaseID = String(runs + 1)
av.target = targetsTextField.text!
closureBlock?()
if let delegate = self.summaryButtonIsEnabledDelegate {
delegate.toggleSummaryButton()
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func segmentedControlChanged(_ sender: UISegmentedControl) {
switch segmentedControl.selectedSegmentIndex {
case 0:
av.shift = 1
case 1:
av.shift = 2
case 2:
av.shift = 3
default:
av.shift = 1
}
}
func configureID(model: ActualValues) {
av = model
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String, int: Int) -> Bool {
let text = (idTextField.text! as NSString).replacingCharacters(in: range, with: string)
if text.isEmpty {
idCheckButton.isEnabled = false
} else {
idCheckButton.isEnabled = true
}
return true
}
}
What should I add to that func?
Connect this #IBAction to both text fields, for Editing Changed:
#IBAction func textFieldEdited(_ sender: Any) {
// reset to disabled every time a text field value changes
// will be set to enabled if data is validated
idCheckButton.isEnabled = false
// make sure idTextField has text
guard let idText = idTextField.text, idText != "" else {
return
}
// make sure targetsTextField has text
guard let targetsText = targetsTextField.text, targetsText != "" else {
return
}
// make sure targetsTextField has only numbers
guard targetsText.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil else {
return
}
// enable the button
idCheckButton.isEnabled = true
}
This will be called with every character entered in either of the fields. It:
first resets the button to .isEnabled = false
then checks to see if the id text field has text
then checks to see if the targets text field has text
then checks to see that the targets field has only numbers
If it makes it through all 3 checks, it sets the button to .isEnabled = true
Try create a function call validator() . all your textField should be add
textField.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: .editingChanged)
#objc func textFieldDidChange(_ textField: UITextField) {
// TODO : Validate all of your textField value here
}
Instead of
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String, int: Int) -> Bool {
let text = (idTextField.text! as NSString).replacingCharacters(in: range, with: string)
if text.isEmpty {
idCheckButton.isEnabled = false
} else {
idCheckButton.isEnabled = true
}
return true
}
Try this
// Add these variables
var idValid = false
var targetsValid = false
func textFieldDidChangeSelection(_ textField: UITextField) {
if textField == idTextField {
// Verify id has text
if textField.text! != "" {
idValid = true
} else {
idValid = false
}
}
if textField == targetsTextField {
// Verify targets is numeric
if textField.text!.isNumeric {
targetsValid = true
} else {
targetsValid = false
}
}
if idValid && targetsValid {
// Both valid enable
idCheckButton.isEnabled = true
} else {
// Not both valid disable
idCheckButton.isEnabled = false
}
}
And you will have to add this extension for String to verify a String as a numeric value - add a new blank Swift file to your project called 'StringExtension' and add:
import Foundation
import UIKit
extension String {
var isNumeric: Bool {
guard self.count > 0 else { return false }
let nums: Set<Character> = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
return Set(self).isSubset(of: nums)
}
}
I have use Eureka framework to create a simple custom row, But validation not work, how can I validate the textfield inside that row ? I have researched on Google but nothing can help. Can anyone give me some help ?
public class TitleAndTextFieldCellModel: NSObject {
// MARK: - Variable
public var title: String = ""
public var placeHolder: String = ""
public var inputValue: String = ""
public var object: Any?
// MARK: - Init
public init(title: String, placeHolder: String = "", inputValue: String = "", object: Any? = nil) {
self.title = title
self.placeHolder = placeHolder
self.inputValue = inputValue
self.object = object
}
}
public class TitleAndTextFieldCell: Cell<TitleAndTextFieldCellModel>, CellType {
// MARK: - Outlets
#IBOutlet weak public var titleLabel: UILabel!
#IBOutlet weak public var inputTextField: UITextField!
override public func setup() {
super.setup()
selectionStyle = .none
inputTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
}
override public func update() {
super.update()
if let model = row.value {
titleLabel.text = model.title
inputTextField.placeholder = model.placeHolder
inputTextField.text = model.inputValue
}
}
#objc func textFieldDidChange(_ textField: UITextField) {
self.row.value?.inputValue = textField.text ?? ""
}
}
final public class TitleAndTextFieldRow: Row<TitleAndTextFieldCell>, RowType {
required public init(tag: String?) {
super.init(tag: tag)
cellProvider = CellProvider<TitleAndTextFieldCell>(nibName: "TitleAndTextFieldCell")
}
}
And this is how I use:
<<< TitleAndTextFieldRow() {
$0.value = TitleAndTextFieldCellModel(title: "Name")
$0.add(rule: RuleRequired(msg: "Field required"))
$0.validationOptions = .validatesOnChangeAfterBlurred
}.cellUpdate({ (cell, row) in
if !row.isValid {
cell.inputTextField.layer.borderWidth = 1
cell.inputTextField.layer.borderColor = UIColor.red.cgColor
}
})
I think I found the answer by myself. For those who need please do something like the code below:
#objc func textFieldDidChange(_ textField: UITextField) {
if textField.text == "" {
self.row.validationErrors.append(ValidationError(msg: "Required"))
self.row.validate()
}
self.row.value?.inputValue = textField.text ?? ""
}
I'm setting up a new application for iPhone and I want to add users input information into my database only if the text field is not empty.
There are 4 text fields but just one has to be complete to update my database.
Swift and iOS coding are new to me.
Here the code I want to improve:
#IBAction func confirmButtonWasPressed(_ sender: UIButton) {
print("Redirection to confirmation screen.")
if confirmpasswordTextField.text != "" {
print("Updating informations.")
// Read values from text fields
let userName = newusernameTextField.text
let userMail = newmailTextField.text
let userPhone = newphoneTextField.text
let userPassword = newpasswordTextField.text
if userName?.isEmpty ?? true {
print("textField is empty")
} else {
print("textField has some text")
}
if userMail?.isEmpty ?? true {
print("textField is empty")
} else {
print("textField has some text")
}
if userPhone?.isEmpty ?? true {
print("textField is empty")
} else {
print("textField has some text")
}
if userPassword?.isEmpty ?? true {
print("textField is empty")
} else {
print("textField has some text")
}
}else{
print("Error: Please enter your password.")
}
}
I want to reduce this function and get input if there have some.
I can do it with this code but I believe there has a short way to do that.
Thanks.
extension String {
public var isBlank: Bool {
let trimmed = trimmingCharacters(in: .whitespacesAndNewlines)
return trimmed.isEmpty
}
}
#IBAction func confirmButtonWasPressed(_ sender: UIButton) {
validateLogin()
}
func validateLogin(){
guard let username = userNameTextfield.text, !username.isBlank else {
return
}
guard let password = passwordTextField.text, !password.isBlank else {
return
}
}
Just use the delegate and a small rewrite for the UITextField so you have the name it has in the Database. In whichever controller you are just do:
class TextField: UITextField {
var nameInDataBase: String
}
class MyViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var newusernameTextField: TextField!
#IBOutlet var newmailTextField: TextField!
#IBOutlet var newphoneTextField: TextField!
#IBOutlet var newpasswordTextField: TextField!
func viewDidLoad(_ animated: Bool) {
super.viewDidLoad()
[newusernameTextField, newmailTextField, newphoneTextField, newpasswordTextField].forEach { $0.delegate = self }
newusernameTextField.nameInDataBase = "newUserName"
newmailTextField.nameInDataBase = "newMail"
/// etc.
}
func textFieldDidEndEditing(_ textField: UITextField) {
guard
let enteredText = textField.text,
let field = textField as? TextField
else {
print ("nothing added or not TextField field")
}
logInDataBase(field.nameInDataBase, enteredText)
}
If you need more info to log stuff in the database, it is just a matter of adding that info as variables of the child class of UITextField
I have to make validation on ui text field which used in library called RSFloatInputView.
Here is my xib
import UIKit
import RSFloatInputView
class TextInputLayout: UIView {
#IBOutlet weak var revealButton: UIButton!
#IBOutlet weak var warningLabel: UILabel!
#IBOutlet weak var rsFloatingView: RSFloatInputView!
var contentView: UIView?
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
contentView = loadViewFromNib()
contentView!.frame = bounds
contentView!.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
addSubview(contentView!)
}
func loadViewFromNib() -> UIView! {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "TextInputLayout", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
revealButton.tintColor = Color.grayColor()
warningLabel.textColor = UIColor.red
return view
}
}
I want to implement this in this view controller, when i click on next button
import UIKit
import DLRadioButton
class SecureWalletViewController: UIViewController,UITextFieldDelegate {
#IBOutlet weak var securityPinStackView: UIStackView!
#IBOutlet weak var securityPin: TextInputLayout!
#IBOutlet weak var confirmSecurityPin: TextInputLayout!
#IBAction func onNextButtonTap(_ sender: Any) {
}
func textInputLayout(at index:Int) -> TextInputLayout {
return securityPinStackView.arrangedSubviews[index] as! TextInputLayout
}
}
Use validations for UITextFieldDelegate method like given below:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return true
}
Or use custom validation function Here
Iam using this
// add func in swift class
struct validatorConstants{
static let errorMsg = "your error messages"
static let customMsg = "your error messages"
static let emailMsg = "your error messages"
}
class Validators: NSObject {
//MARK: Validation on any Empty TextField
func validators(TF1:UITextField,errorMsg:String = validatorConstants.errorMsg,fieldName:String = "") -> Bool {
var error = validatorConstants.errorMsg
if fieldName.count > 0 {
error = fieldName + " is missing"
}
if TF1.text?.isEmpty == true{
kAppDelegate.showNotification(text: error)
return false
}
return true
}
//MARK: Validation on any Email TextField
func validatorEmail(TF1:UITextField,errorMsg:String = validatorConstants.errorMsg ,errorMsgEmail:String = validatorConstants.emailMsg,fieldName:String = "Email" ) -> Bool {
var error = validatorConstants.errorMsg
if fieldName.count > 0 {
error = fieldName + " is missing"
}
if TF1.text?.isEmpty == true{
kAppDelegate.showNotification(text: error)
return false
}
if TF1.text?.isValidEmail == false{
kAppDelegate.showNotification(text: errorMsgEmail)
return false
}
return true
}
}
// call this func like this
// your ViewController
var validator:Validators!
// In viewdidload
validator = Validators()
// call this func on button Action
guard validator.validators(TF1: txtfied,fieldName: "your txtfield name") == false
else
{
//do something what you want
return
}
// Its works for me hope its works for you
I'd recommend to use a UITextField subclass with 2 UI states (regular / invalid) and a validation rule (e.g. not empty / match regex / etc)
class ValidationTextField: UITextField {
enum ValidationRule {
case notEmpty
// case matchRegex(regex: NSRegularExpression)
// ...
}
var validationRule: ValidationRule?
private(set) var isValid:Bool = true {
didSet {
updateUIForCurrentState()
}
}
// Call this method on the "next" button click
// (or from the delegate on the textFieldDidEndEditing event for early validation)
func validate() {
guard let rule = validationRule else {
// nothing to validate
return;
}
switch rule {
case .notEmpty:
if let length = text?.count {
isValid = length > 0
}
else {
isValid = false
}
// process other cases (e.g. matchRegex)
}
}
/// Configure your state-specific layout here.
private func updateUIForCurrentState() {
// Current implementation adds a red border in case of invalid input
if isValid {
layer.borderWidth = 0
layer.borderColor = nil
}
else {
layer.borderWidth = 2
layer.borderColor = UIColor.red.cgColor
}
}
}
You can use SwiftValidator, It is rule based validator.
let validator = Validator()
//Register the fields that you want to validate
validator.registerField(fullNameTextField, rules: [RequiredRule(), FullNameRule()])
#IBAction func signupTapped(sender: AnyObject) {
validator.validate(self)
}
I am creating a sign up view(form) with Fullname, Email, Password and Verify Password as textfields. And I want to use validations as "mandatory field" incase of error while user inputs the data. I have created extension for UITextField and String. But I found that textFieldDidEndEditing is not called and validations are not checked. Anyone help me to solve this issue ?
//UITextField
import UIKit
extension UITextField {
func addLeftPadding() {
let view = UIView(frame:CGRect(x: 0, y: 0, width: 10, height: 40))
self.leftView = view
self.leftViewMode = .always
}
func addWarning(warningMessage message:String) {
self.removeWarning()
let label = UILabel(frame: CGRect(x:self.frame.minX,y: self.frame.maxY + 2 , width:self.frame.width,height:15))
label.tag = self.tag
label.text = message
self.superview?.addSubview(label)
}
func removeWarning() {
for subView in (self.superview?.subviews)! {
if let label = subView as? UILabel , label.tag == self.tag {
label.removeFromSuperview()
}
}
}
}
//String
import UIKit
extension String {
var isEmail: Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluate(with: self)
}
}
//SignUpController
import UIKit
import Material
class SignUpController: UIViewController {
#IBOutlet weak var fullName: TextField!
#IBOutlet weak var Email: TextField!
#IBOutlet weak var PasswordField: TextField!
#IBOutlet weak var NewPassword: TextField!
override func viewDidLoad() {
super.viewDidLoad()
prepareFullNameField()
prepareEmailField()
preparePasswordField()
prepareNewPasswordField()
self.fullName.delegate = self
self.Email.delegate = self
self.PasswordField.delegate = self
self.NewPassword.delegate = self
fullName.leftViewMode = UITextFieldViewMode.always
fullName.returnKeyType = UIReturnKeyType.next
Email.leftViewMode = UITextFieldViewMode.always
Email.returnKeyType = UIReturnKeyType.next
PasswordField.leftViewMode = UITextFieldViewMode.always
PasswordField.returnKeyType = UIReturnKeyType.next
NewPassword.leftViewMode = UITextFieldViewMode.always
NewPassword.returnKeyType = UIReturnKeyType.done
//prepareResignResponderButton()
// Do any additional setup after loading the view.
}
}
extension SignUpController {
fileprivate func prepareFullNameField() {
fullName.placeholder = "Name"
fullName.textColor = UIColor.white
}
fileprivate func prepareEmailField() {
Email.placeholder = "Email"
Email.textColor = UIColor.white
}
fileprivate func preparePasswordField() {
PasswordField.placeholder = "Password"
PasswordField.textColor = UIColor.white
}
fileprivate func prepareNewPasswordField() {
NewPassword.placeholder = "Verify Password"
NewPassword.textColor = UIColor.white
}
}
extension SignUpController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool { //delegate method
self.view.endEditing(true)
if textField == fullName {
fullName.resignFirstResponder()
//Email.becomeFirstResponder()
Email.becomeFirstResponder()
}
else if textField == Email {
Email.resignFirstResponder()
PasswordField.becomeFirstResponder()
}
else if textField == PasswordField {
PasswordField.resignFirstResponder()
NewPassword.becomeFirstResponder()
}
else{
NewPassword.resignFirstResponder()
}
return true
}
func dismissKeyboard() {
fullName.resignFirstResponder()
Email.resignFirstResponder()
PasswordField.resignFirstResponder()
NewPassword.resignFirstResponder()
}
// public func textFieldDidEndEditing(_ textField: UITextField) {
// (textField as? ErrorTextField)?.isErrorRevealed = false
// print("none")
// }
func textFieldDidEndEditing(_ textField: UITextField) {
switch textField {
case fullName:
if fullName == nil {
textField.addWarning(warningMessage: "mandatory_field")
print("hmmmmmmmmm")
}else{
textField.removeWarning()
}
case Email:
if Email == nil {
textField.addWarning(warningMessage:"mandatory_field")
}else{
textField.removeWarning()
}
case PasswordField:
if PasswordField == nil {
textField.addWarning(warningMessage: "invalid_email")
}else{
textField.removeWarning()
}
case NewPassword:
if NewPassword == nil {
textField.addWarning(warningMessage: "minimum_password")
}else{
textField.removeWarning()
}
default:
print("default")
}
}
public func textFieldShouldClear(_ textField: UITextField) -> Bool {
(textField as? ErrorTextField)?.isErrorRevealed = false
print("good")
return true
}
// func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// (textField as? ErrorTextField)?.isErrorRevealed = true
//
// print("ok")
// return true
// }
}
Please try the below code to validate the text fields.
if (textField.text.isEmpty) {
let alert = UIAlertView()
alert.title = "No Text"
alert.message = "Please Enter Text In The Box"
alert.addButtonWithTitle("Ok")
alert.show()
}
I have also used the same code for validating text field in Swift version 3.