How to trigger code anytime a UItextfield is empty - swift

I would like to have code for anytime a UItextfield is empty. Not just on the viewdidload but all the time. I tried putting something like if textField.isEmpty == true in the editing changed action although the issue I was having is if you type more than 5 characters and then hold down backspace the code doesn't get triggered. Any ideas for what to do?

Hi you need to subscribe on editing changed 
How to check if the field is empty?
let textField = UITextField()
textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
#objc func textChanged () {
if textField.text == "" || textField.text == nil {
print("IS EMPTY")
} else {
print("NON EMPTY")
}
}
How to set max length to UITextField
class ViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
let textField = UITextField()
textField.delegate = self
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let textFieldText = textField.text,
let rangeOfTextToReplace = Range(range, in: textFieldText) else {
return false
}
let substringToReplace = textFieldText[rangeOfTextToReplace]
let count = textFieldText.count - substringToReplace.count + string.count
return count <= 5
}
}

Related

Why does text field content always start with a capital letter? [duplicate]

I would like to force lowercase in an UITextfield when the user is typing.
I came out so far with this code, but seems like it's not lowering characters.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if string.characters.count == 0 {
return true
}
let currentText = textField.text ?? ""
let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string.lowercaseString)
switch textField {
// Allow only lower-case vowels in this field,
// and limit its contents to a maximum of 6 characters.
case userNameTextField:
return prospectiveText.characters.count <= 27
default:
return true
}
}
First you should set following property on your textfield to restrict auto capitalisation:
textfield.autocapitalizationType = UITextAutocapitalizationType.None
And this is how you can restrict it further:
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
if let _ = string.rangeOfCharacterFromSet(NSCharacterSet.uppercaseLetterCharacterSet()) {
// Do not allow upper case letters
return false
}
return true
}
UPDATED FOR SWIFT 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let _ = string.rangeOfCharacter(from: .uppercaseLetters) {
// Do not allow upper case letters
return false
}
return true
}
You could do like this and lowercase the entire string when something has changed.
textfield.addTarget(self, action: "textViewChanged", forControlEvents: .EditingChanged);
func textViewChanged(){
textfield.text = textfield.text?.lowercaseString;
}
for swift 3 users, the above code given by Abhinav is just converted to the following
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let _ = string.rangeOfCharacter(from:NSCharacterSet.uppercaseLetters) {
return false
}
return true
}
if you want to convert all input characters to lower case you should do this code:
Swift 4:
in override func viewDidLoad() add this:
textfield.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
and then add this function to your class:
#objc func textFieldDidChange(_ textField: UITextField) {
if let text:String = textfield.text {
DispatchQueue.main.async {
self.textfield.text = text.lowercased()
}
}
}
it is necessary to change it in main thread.

How do you set a maximum number value for a textfield in Swift that's flexible?

I would like to use the
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
}
I'm fetching a number from firebase which will be the maximum they will be allowed to type into a textfield. Fetching the number is easy, how do I set this maximum for the UITextField?
Just make a class and fill maximum number in storyboard as like:
import UIKit
#IBDesignable
class CustomTextField: UITextField {
#IBInspectable var maxLength: Int = Int.max {
didSet {
addTarget(self, action: #selector(limitLength), for: .editingChanged)
}
}
override func didMoveToWindow() {
super.didMoveToWindow()
addTarget(self, action: #selector(limitLength), for: .editingChanged)
}
#objc private func limitLength() {
guard let prospectiveText = text, prospectiveText.count > maxLength else {
return
}
let selection = selectedTextRange
text = String(prospectiveText.prefix(maxLength))
selectedTextRange = selection
}
}
you can use textField value;
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.text.count <= maximumNumberOfCharachters {
...
}
return false
}

textfielddidbegin editing not updating label

My swift code below goal is when the user enters something into textfield tt it reflects it in currentPageLabel. The func that I thought would do this is having no effect. Nothing I enter into the textfield displays on the label. All of my code does not use a storyboard.
var currentPageLabel = UILabel()
var tt = UITextfield()
func textFieldDidBeginEditing(_ textField: UITextField) {
currentPageLabel.text = tt.text
}
Try this UITextFieldDelegate method:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
currentPageLabel.text = text
return true
}
You can use addTarget feature in this case! Just add target to your textField in viewDidload method, and add selector method marked with #objc textFieldDidChange. Inside textFieldDidChange function set text to your label!
textfield.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
#objc func textFieldDidChange(_ textField: UITextField) {
currentPageLabel.text = textField.text
}

Swift UI Delegate methods not being working

I am trying to have my inputs inside of my UITextField show up in the debugger console, when I am typing in the created TextField however the Delegate Methods don't seem to be responding. I am expecting to see my print statement that are seen below for my UIdelegate methods, like when I first started typing, while I type, and when I press the 'return key'. All delegate methods do not seem to be activated, and I am not sure how to make my Textfield link to the delegate method directly. In addition, I have another UITextField (Not shown here), would I have to 'addTarget' to differentiate between the two?
class ViewController: UIViewController, UITextFieldDelegate {
let createUserName: UITextField = {
var myTextField = UITextField ()
myTextField.translatesAutoresizingMaskIntoConstraints = false
myTextField.placeholder = "Username" //set placeholder text
myTextField.font = UIFont.systemFont(ofSize: 14) // set font size of text field
myTextField.layer.borderWidth = 1.0 //set width
myTextField.layer.borderColor = UIColor.red.cgColor//set background color to a ui color
myTextField.layer.backgroundColor = UIColor.white.cgColor
myTextField.layer.cornerRadius = myTextField.frame.height/2
myTextField.autocorrectionType = .no // disable autocorrect when typing for .no, enable with .yes
myTextField.isSecureTextEntry = false// masked text
myTextField.keyboardType = .default //keyboard style is set to default
myTextField.returnKeyType = .default //retuen key text changed to "Done" instead of return
myTextField.clearButtonMode = .whileEditing
myTextField.delegate = self as? UITextFieldDelegate
return myTextField
}()
override func viewDidLoad() {
super.viewDidLoad()
createUserName.delegate = self
view.addSubview(createUserName)
setupUserName()
}
//UITextField Delegate methods
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
print("textfield should begin editting")
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
print("text field edit")
}
//see string that is typed in debugger for use to validate password and crossreference username
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let textFieldString = textField.text, let swtRange = Range(range, in: textFieldString) {
let fullString = textFieldString.replacingCharacters(in: swtRange, with: string)
print("FullString: \(fullString)")
}
return true
}
//dismiss keyboard when return button is pressed
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
print("text field return")
return true
}
}
Your viewController should inherit from UITextFieldDelegate
class YourViewController : UIViewController, UITextFieldDelegate {
// your code
}
Also in your ViewDidLoad, move your createUsername.delegate = self to last line.
That string:
myTextField.delegate = self as? UITextFieldDelegate
tell us that your VC don't directly conform protocol UITextFieldDelegate...
If you conformed swift doesn't add as? cast ...

Swift - Automatically jump to next text field when not empty

I am working on a game in which the user has to type out the past tense of a verb. My view contains small textfield boxes that only accept one character. As of now I am trying to automatically jump to the next textfield when the former contains a letter.
I want to keep doing this until all the boxes are filled. The user should also be able to go back one box using the return button on the keyboard.
Below is the code I am currently using, but it is not jumping to the next textfield. What am I doing wrong?
var game: Game? {
didSet {
if var answerContent = game?.answer {
let views = (0..<answerContent.characters.count).map { _ in UITextField(frame: CGRect(x: 0, y: 0, width: 40, height: 40)) }
for textField in views {
textField.backgroundColor = UIColor.white
textField.textColor = Constants.MAIN_THEME_COLOR
textField.textAlignment = NSTextAlignment.center
textField.delegate = self
textField.returnKeyType = .next
textField.tag = views.index(of: textField)! + 1
self.container.addArrangedSubview(textField)
views.first?.becomeFirstResponder()
}
}
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
let textLength = text.characters.count + string.characters.count - range.length
return textLength <= 1
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
print("Test")
nextField.becomeFirstResponder()
} else {
print("Test2")
textField.resignFirstResponder()
}
return false
}
Updated code (24-04-2017) - Returns nil when trying to jump to the next textField
var game: Game? {
didSet {
if var answerContent = game?.answer {
let views = (0..<answerContent.characters.count).map { _ in UITextField(frame: CGRect(x: 0, y: 0, width: 40, height: 40)) }
for textField in views {
textField.backgroundColor = UIColor.white
textField.textColor = Constants.MAIN_THEME_COLOR
textField.textAlignment = NSTextAlignment.center
textField.delegate = self
textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
textField.tag = views.index(of: textField)! + 1
self.container.addArrangedSubview(textField)
}
views.first?.becomeFirstResponder()
}
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
let textLength = text.characters.count + string.characters.count - range.length
return textLength <= 1
}
func textChanged(sender: UITextField) {
if (sender.text?.characters.count)! > 0 {
print("Entered")
let nextField = textField?.superview?.viewWithTag(textField.tag + 1) as UIResponder!
if (nextField != nil) {
nextField?.becomeFirstResponder()
} else {
print("Error: nil found")
}
} else {
print("Removed")
textField?.resignFirstResponder()
}
}
Answer:
var index: NSInteger = 0
for textField in views {
textField.backgroundColor = UIColor.white
textField.textColor = Constants.MAIN_THEME_COLOR
textField.textAlignment = NSTextAlignment.center
textField.autocapitalizationType = UITextAutocapitalizationType.none
textField.delegate = self
textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
textField.tag = index
self.container.addArrangedSubview(textField)
index+=1
}
func textChanged(sender: UITextField) {
if (sender.text?.characters.count)! > 0 {
let nextField = sender.superview?.viewWithTag(sender.tag + 1) as UIResponder!
nextField?.becomeFirstResponder()
} else {
sender.resignFirstResponder()
}
}
I suggest that you should add a target to the control event .valueChanged:
// for each text field
textField.addTarget(self, action: #selector(textChanged), for: .valueChanged)
Implement textChanged as follows:
func textChanged(sender: UITextField) {
if sender.text.characters.length > 0 {
let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField
nextField?.becomeFistResponder()
}
}
Follow the code:
import UIKit
// used this to set max characters of UITextField in the storyboard
private var __maxLengths = [UITextField: Int]()
extension UITextField {
#IBInspectable var maxLength: Int {
get {
guard let l = __maxLengths[self] else {
return 150 // (global default-limit. or just, Int.max)
}
return l
}
set {
__maxLengths[self] = newValue
addTarget(self, action: #selector(fix), for: .editingChanged)
}
}
func fix(textField: UITextField) {
let t = textField.text
textField.text = t?.safelyLimitedTo(length: maxLength)
}
}
extension String
{
func safelyLimitedTo(length n: Int)->String {
let c = self.characters
if (c.count <= n) { return self }
return String( Array(c).prefix(upTo: n) )
}
}
class ViewController: UIViewController {
#IBOutlet var input1: UITextField!
#IBOutlet var input2: UITextField!
#IBOutlet var input3: UITextField!
#IBOutlet var input4: UITextField!
#IBOutlet var input5: UITextField!
#IBOutlet var input6: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
setup()
// Do any additional setup after loading the view.
}
func setup() {
input1.tag = 1
input2.tag = 2
input3.tag = 3
input4.tag = 4
input5.tag = 5
input6.tag = 6
input1.addTarget(self, action: #selector(textChanged), for: .editingChanged)
input2.addTarget(self, action: #selector(textChanged), for: .editingChanged)
input3.addTarget(self, action: #selector(textChanged), for: .editingChanged)
input4.addTarget(self, action: #selector(textChanged), for: .editingChanged)
input5.addTarget(self, action: #selector(textChanged), for: .editingChanged)
input6.addTarget(self, action: #selector(textChanged), for: .editingChanged)
}
func textChanged(sender: UITextField) {
if (sender.text?.characters.count)! == 1 {
let nextField = sender.superview?.viewWithTag(sender.tag + 1) as UIResponder!
nextField?.becomeFirstResponder()
} else if (sender.text?.characters.count)! == 0 {
let nextField = sender.superview?.viewWithTag(sender.tag - 1) as UIResponder!
nextField?.becomeFirstResponder()
}
}
}
Update for Swift 4
In viewDidLoad() for each text field,
textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
Then, add this function,
#objc func textChanged(sender: UITextField) {
if (sender.text?.count)! > 0 {
let nextField = self.view.viewWithTag(sender.tag + 1) as? UITextField
nextField?.becomeFirstResponder()
}
}