Where do I call my function so it successfully updates my UI? - swift

I have written the following function to ensure my user fills in a textField before being able to continue.
func validateFields() -> String {
if textfield.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
return "Please fill in textField"
}
return "A-OK."
}
func updateUI() {
let verdict = validateFields()
if verdict == "A-OK." {
self.buttonOne.alpha = 1
}
}
override func viewDidLoad() {
super.viewDidLoad()
updateUI()
}
However, once the textField has been filled in, the above code fails to update the UI. I know I am missing out on something trivial here, I just cannot wrap my head around what. I'd really appreciate the help.

Use text textFieldDidEndEditing, textFieldDidBeginEditing, textFieldShouldReturn, etc. according to your requirement.
But I think delegate "textFieldShouldReturn" works fine with your requirement.
You just need to add you function updateUI() in this delegate.

That's easy you can create an outlet of your text fields and give its
delegate to self in viewDidLoad() method
#IBOutlet var txtfld: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
txtfld.delegate = self
}
// UITextField Delegates
func textFieldDidBeginEditing(_ textField: UITextField) {
print("TextField did begin editing method called")
}
func textFieldDidEndEditing(_ textField: UITextField) {
print("TextField did end editing method called")
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
print("TextField should begin editing method called")
return true;
}
func textFieldShouldClear(_ textField: UITextField) -> Bool {
print("TextField should clear method called")
return true;
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
print("TextField should end editing method called")
return true;
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
print("While entering the characters this method gets called")
return true;
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
print("TextField should return method called")
textField.resignFirstResponder();
return true;
}
}
I suggest for calling your method you should use your updateUI()
function in textFieldShouldReturn(_ textField: UITextField) this
method.

I suppose you can easily bind you text view to a local property and observer changes on that property. And when everything is valid, you can enable your buttonOne and use the value of that property in future computations.
var myTextFieldData: String {
didSet {
updateUI()
}
}
Also, keep in mind that you'll also have to implement the UITextField delegate in order to bind your textField with myTextFieldData:
textField.delegate = self
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
myTextFieldData = string
return true
}

Related

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
}

Swift - How to limit the a few specific text field only allow to insert int?

How to limit the few specific text field only allow to insert int?
not all text fields. only a few specific ones.
Thank you.
Try this one.
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var yourTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
yourTextField.delegate = self
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//For mobile numer validation
if textField == yourTextField {
//Add specific int numbers
let allowedCharacters = CharacterSet(charactersIn:"0123 ")//Here change this characters based on your requirement
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet)
}
return true
}
}
Tried setting your textField's keyboard type?
yourTextField.keyboardType = .numberPad
Can also look into the delegate method
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return true
}
You can from there add logic to return true or false if the textField's selection meets your requirements

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
}

How can I disable this done button until these two text fields have values?

My goal is for the done button to be disabled while both of these text fields are empty. I have the logic for the top button, but as soon the top text field "taskNameTextFIeld" has at least one character, the done button is enabled. I don't want users to be able to press done while "timeTextField" is empty. You can see what I have so far in textField().
import UIKit
protocol AddNewTaskViewControllerDelegate: class {
func addNewTaskViewControllerDidCancel(_ controller: AddNewTaskViewController)
func addNewTaskViewController(_ controller: AddNewTaskViewController,
didFinishAdding item: TaskData)
}
class AddNewTaskViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var taskNameTextFIeld: UITextField!
#IBOutlet weak var timeTextFIeld: UITextField!
#IBOutlet weak var doneBarButton: UIBarButtonItem!
weak var delegate: AddNewTaskViewControllerDelegate?
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let oldText = textField.text! as NSString
let newText = oldText.replacingCharacters(in: range, with: string) as NSString
doneBarButton.isEnabled = newText.length > 0
return true
}
#IBAction func cancel(_ sender: Any) {
delegate?.addNewTaskViewControllerDidCancel(self)
}
#IBAction func done(_ sender: Any) {
let item = TaskData()
item.task = taskNameTextFIeld.text!
item.time = timeTextFIeld.text!
delegate?.addNewTaskViewController(self, didFinishAdding: item)
}
func textFieldShouldReturn(_ TextField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
return nil
}
override func viewDidLoad() {
super.viewDidLoad()
self.taskNameTextFIeld.delegate = self;
self.timeTextFIeld.delegate = self;
// Do any additional setup after loading the view.
}
}
The issue is you aren't checking both fields. Change:
doneBarButton.isEnabled = newText.length > 0
To an actual check of things:
if taskNameTextFIeld.text.length > 0 && timeTextFIeld.text.length > 0 {
doneBarButton.isEnabled = newText.length > 0
}
Also, I'd recommend changing the names of both text fields to be Field and not Field.
Here is some detail on how I solved the problem. Text fields themselves did not have a length member so I compared character count instead.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let oldText = textField.text! as NSString
let newText = oldText.replacingCharacters(in: range, with: string) as NSString
//doneBarButton.isEnabled = newText.length > 0
if (taskNameTextFIeld.text?.characters.count)! > 0 && (timeTextFIeld.text?.characters.count)! > 0 {
doneBarButton.isEnabled = newText.length > 0
}
return true
}

textField method of UITextFieldDelegate not being called

I think I'm probably doing something stupid but I'm going to ask the question anyway.
I cannot see the UITextFieldDelegate method textField being called. I've created a simple program with print statements showing all other delegate methods get called okay, but not this one. Here's the program code:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
//MARK: Properties
#IBOutlet weak var testTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
testTextField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool {
print("textFieldShouldReturn")
textField.resignFirstResponder()
return true
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
print("textFieldShouldBeginEditing")
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
print("textFieldDidBeginEditing")
print("Leaving textFieldDidBeginEditing")
}
func textField(textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
print("textField")
print("Leaving textField")
return true
}
func textFieldDidEndEditing(textField: UITextField) {
print("textFieldDidEndEditing")
print("textField = \(textField.text)")
print("Leaving textFieldDidEndEditing")
}
}
Ands that's it. I have a ViewController with a UITextField added in Interface Builder. Entering text shows the other delegate methods are being called okay. I'm using Xcode 7.3.1.
Any help much appreciated and apologies up front if this is a dumb question - which I expect it is.
I think you are facing the issue because of the typo in the function.
This is what you are using:
func textField(textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {...}
This is how the function should be:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {...}
just copy and paste this lines in your ViewDidLoad and have a try with this textField
let txtField: UITextField = UITextField(frame: CGRect(x: 0, y: 0, width: 400.00, height: 30.00));
txtField.delegate = self