I created a custom text field and call a function every time the user type on it, the problem is how can I know what function was going to call.
Here is my code for custom UITextField that call a function every type.
class CustomTextField: UITextField, UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
NSObject.cancelPreviousPerformRequests(
withTarget: self,
selector: #selector(callFunction),
object: textField)
self.perform(
#selector(callFunction),
with: textField,
afterDelay: 0.5)
return true
}
#objc func callFunction(textField: UITextField) {
functionToBeCall()
}
}
As you can see in my code, I need that functionToBeCall() to be change in every class I use it, and that class was reusable so I can't set a static method in it. How can I achieve that?
Use delegation:
protocol CustomTextFieldDelegate: class {
func customTextFieldDidChange(_ customTextField: CustomTextField)
}
class CustomTextField: UITextField, UITextFieldDelegate {
weak var customDelegate: CustomTextFieldDelegate?
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
NSObject.cancelPreviousPerformRequests(
withTarget: self,
selector: #selector(callFunction),
object: textField)
self.perform(
#selector(callFunction),
with: textField,
afterDelay: 0.5)
return true
}
#objc func callFunction(textField: UITextField) {
customDelegate?.customTextFieldDidChange(self)
}
}
Any class that uses a CustomTextField should adopt the CustomTextFieldDelegate protocol, implement the callback function, and set itself as the customDelegate on the CustomTextField.
Example Usage:
class ViewController: UIViewController, CustomTextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let customTextField = CustomTextField(frame: CGRect(x: 100, y: 100, width: 200, height: 50))
view.addSubview(customTextField)
customTextField.customDelegate = self
}
func customTextFieldDidChange(_ customTextField: CustomTextField) {
print("custom field was changed")
}
}
Related
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
}
I am trying to limit the number of characters that the user can enter to 1.
class ActivationViewController: UIViewController , UITextFieldDelegate{
#IBOutlet weak var activationCodeTextField1: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.activationCodeTextField1.addTarget(self, action: #selector(self.textField1DidChange(_:)), for: UIControl.Event.editingChanged)
self.activationCodeTextField1.delegate = self
}
#IBAction func textField1DidChange(_ sender: AnyObject) {
print("TextField1DidChange")
}
func activationCodeTextField1(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// You can check for other things besides length here as well.
print("isValidLength: ", isValidLength(textField: activationCodeTextField1, range: range, string: string))
return isValidLength(textField: activationCodeTextField1, range: range, string: string)
}
private func isValidLength(textField: UITextField, range: NSRange, string: String) -> Bool {
let length = ((textField.text ?? "").utf16).count + (string.utf16).count - range.length
return length <= 1
}
}
However, the function activationCodeTextField1 doesn't get triggered and this line inside of it doesn't print anything:
print("isValidLength: ", isValidLength(textField: activationCodeTextField1, range: range, string: string))
Any idea what I've done wrong?
You can't change the name of delegate methods. The correct function is
optional func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool
Documentation
You have not called any of the method from UITextFieldDelegate protocol. Please checkout link to find methods in UITextFieldDelegate protocol.
https://developer.apple.com/documentation/uikit/uitextfielddelegate
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
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
}
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