Set the maximum character length of a UITextField in Swift
Solution 1
-
Your view controller should conform to
UITextFieldDelegate
, like below:class MyViewController: UIViewController, UITextFieldDelegate { }
-
Set the delegate of your textfield:
myTextField.delegate = self
-
Implement the method in your view controller:
textField(_:shouldChangeCharactersInRange:replacementString:)
All together:
class MyViewController: UIViewController, UITextFieldDelegate // Set delegate to class
@IBOutlet var mytextField: UITextField // textfield variable
override func viewDidLoad() {
super.viewDidLoad()
mytextField.delegate = self // set delegate
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text
let newString: NSString = currentString.stringByReplacingCharactersInRange(range, withString: string)
return newString.length <= maxLength
}
For Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let maxLength = 1
let currentString: NSString = (textField.text ?? "") as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
For Swift 5
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let maxLength = 1
let currentString = (textField.text ?? "") as NSString
let newString = currentString.replacingCharacters(in: range, with: string)
return newString.count <= maxLength
}
Allowing only a specified set of characters to be entered into a given text field
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
var result = true
if mytextField == numberField {
if count(string) > 0 {
let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789.-").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
result = replacementStringIsLegal
}
}
return result
}
How to program an iOS text field that takes only numeric input with a maximum length
Solution 2
Modern Swift
Note that much of the example code online regarding this problem is extremely out of date.
Paste the following into any Swift file in your project. (You can name the file anything, for example, "Handy.swift".)
This finally fixes one of the stupidest problems in iOS:
Your text fields now have a .maxLength
.
It is completely OK to set that value in storyboard during development, or, set it in code while the app is running.
// simply have this in any Swift file, say, Handy.swift
import UIKit
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?.prefix(maxLength).string
}
}
It's that simple.
Footnote - these days to safely truncate a String
in swift, you simply .prefix(n)
An even simpler one-off version...
The above fixes all text fields in your project.
If you just want one particular text field to simply be limited to say "4", and that's that...
class PinCodeEntry: UITextField {
override func didMoveToSuperview() {
super.didMoveToSuperview()
addTarget(self, action: #selector(fixMe), for: .editingChanged)
}
@objc private func fixMe() { text = text?.prefix(4) }
}
Phew! That's all there is to it.
(Just BTW, here's a similar very useful tip relating to UITextView, https://stackoverflow.com/a/42333832/294884 )
For the OCD programmer (like me)...
As @LeoDabus reminds, .prefix
returns a substring. If you're incredibly caring, this
let t = textField.text
textField.text = t?.prefix(maxLength)
would be
if let t: String = textField.text {
textField.text = String(t.prefix(maxLength))
}
Enjoy!
Solution 3
In Swift 4, simply use:
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return range.location < 10
}
Solution 4
The same way Steven Schmatz did it but using Swift 3.0 :
//max Length
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 4
let currentString: NSString = textField.text! as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
Solution 5
For Swift 5:
Just write one line to set the maximum character length:
self.textField.maxLength = 10
For more details, see Max character limit of UITextField and allowed characters Swift. (Also credited.)
Related videos on Youtube
Comments
-
ishkur88 over 2 years
I know there are other topics on this, but I can't seem to find out how to implement it.
I'm trying to limit a UITextField to only five characters.
Preferably alphanumeric,
-
,.
, and_
.I've seen this code:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let maxLength = 4 let currentString: NSString = textField.text let newString: NSString = currentString.stringByReplacingCharactersInRange(range, withString: string) return newString.length <= maxLength }
and
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let length = count(textField.text.utf16) + count(string.utf16) - range.length return length <= 10 }
How can I actually implement it? Which "textfield" should I swap out for my custom named UITextField?
-
Leo Dabus over 5 yearsSwift 4 implementation stackoverflow.com/a/46513151/2303865
-
Fattie almost 5 yearsQuick alert - to shorten a
String
in Swift these days you can finally just .prefix(n)
-
-
ishkur88 almost 9 yearsThank you so much for the prompt reply! If I set this one textfield as the delegate would I be able to modify other textfields?
-
Alaeddine almost 9 yearsyes, and you will get the textfield in question (being edited ) as the first parameter
textField
in the methodfunc textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
-
ishkur88 almost 9 yearsBut where would I put in the second parameter? I don't reference myTextField again after I set it as a delegate.
-
ishkur88 almost 9 yearsLike if I wanted to make another textfield 0-9 only for phone numbers.
-
Alaeddine almost 9 yearsevery time a textfield is being edited, the callback
shouldChangeCharactersInRange
is called, this is for all textfields, you receive the callback in the same placeshouldChangeCharactersInRange
and inside this method you can know which textfield is being edited thanks to the passed parametertextField
you can for example give a tag for each textfield and test inside theshouldChangeCharactersInRange
and for each textfield perform the validation of the content -
Alaeddine almost 9 years@ishkur88 I have updated the answer with another example note the
if mytextField == numberField {
to check the textField that is being edited -
Theo Bendixson over 7 yearsDoes this particular solution allow the user to enter a backspace character once the user has hit the character limit? Would we need a way to let backspaces through?
-
J. Doe about 7 yearsSeems legit! Thank you.
-
mylovemhz almost 7 yearsThat all this has to be done to achieve something so common and so simple blows my mind. They couldn't just give us a simple textField.maxLength built-in...anyway your solution is great, thanks!
-
jonathan3087 over 6 yearsWow, best tip I have ever had on SO. I'd up vote it 100 if I could!
-
Alan Scarpa over 6 yearsFor Swift 4, this
self.characters
is deprecated. It is now justlet c = self
-
Vamshi Krishna over 6 yearsCannot we do something like this for regex validation (like phoneNumber, emailId, userName)?
-
Angel G. Olloqui about 6 yearsThe solution is handy but the map of textfields at the top will actually produce a retain cycle.
-
Fattie about 6 yearshi @AngelGarcíaOlloqui - it's an excellent point, in the unusual case where they're not just from storyboards, you'd have to attend to that. Good thinking!
-
Keyhan Kamangar over 5 yearsThanks for your answer, Can u explain maxLengths please?
-
Ankur Lahiry over 5 yearsThe answer I am looking for :D
-
user832 over 5 yearsthis should be the selected answer. Simple and workes well.
-
Slavcho over 5 yearsIt doesnt work. What if you tap in the middle of the string and you can type more than X chars.
-
Leo Dabus over 5 years
super.didMoveToSuperview()
"The default implementation of this method does nothing. Subclasses can override it to perform additional actions whenever the superview changes." Considering it calling super for that method is pointless -
Fattie over 5 yearsan excellent point @LeoDabus , thanks! I'll leave it there to help new programmers with the typical pattern; Happy new year!
-
Leo Dabus over 5 years@Fattie you are welcome. Happy new year for you too.
-
Fattie over 5 years@TheoBendixson , the more modern solution of simply using
. editingChanged
completely handles all such issues. -
cornr over 5 yearsThis does not handle copy and paste
-
Saqib Saud over 5 yearsinstead of range.location < 10, you can use textField.text.length < 10. This solution is simple and elegant.
-
10623169 about 5 yearsThis should be the accepted answer. Works perfectly, with no bugs.
-
zeeshan almost 5 yearsThis is the solution, simple and elegant, with no boilerplate code.
-
ViruMax almost 5 yearsThis solution creates a new issue while typing in other languages like Mandarin, Korean, etc.
-
Hasya almost 5 yearsGood answer. Appreciated.
-
juancazalla almost 5 yearsWARNING FOR THOSE USING THIS SOLUTION! This solution has some problems. One of them is that if the user types at the beginning of the textField, you are going to allow them to type the new character and the last one will be removed, also, the cursor will jump to the last character in the field. Another problem is that if you set the text programmatically, it will allow you to set a text bigger than the limit. Another problem occurs if you undo a change (CMD+Z with an external keyboard) it will crash if you tried to add a digit over the limit previously.
-
Fattie almost 5 yearshi @juancazalla ! the first three are desired behaviors, and depend on what you or the client wants. regarding the external keyboard undo issue, that's a great point, I did not think of testing with an external keyboard! I will try to repo that!
-
Sachin Rana over 4 yearsSuppose I have 2 textfields. Both require different max char limit, one require 10 char and other require 20 char. In that case what approach should I need to follow. Is there any way to make maxLength variable dynamic?
-
Сергей Билык over 4 yearsYou can use this solution: if textField.text?.count >= 12 { return false }
-
Reza Dehnavi about 4 yearsit doesn't work when past a text if you want to work in past action you should add
string.count < MAX_LENGTH
-
iDev about 4 yearsThis cannot work. Location is not the length of the string but the position of the cursor / selelction.
-
Dylan almost 4 yearsit gives me an error saying
Expression type '()' is ambiguous without more context
on prefix -
Dylan almost 4 yearshi @Fattie I posted my question here stackoverflow.com/q/62165247/6800631
-
Leo Dabus almost 4 years@Fattie you need to update the post
textField.text = String(textField.text!.prefix(maxLength))
andtext = String(text!.prefix(4))
-
Leo Dabus almost 4 yearsPrefix returns a substring
-
Leo Dabus almost 4 yearsI think since String started conforming to RangeReplaceableCollection
-
Leo Dabus almost 4 years@Fattie You can safely force unwrap it. Its default value is an empty String. It will NEVER return nil. You can even set it to nil and it wont return nil after that.
-
Fattie almost 4 yearshi @LeoDabus , you know, I wonder if that assumption in the specific UITextField class would confuse newer users; it's not something one can assume generally ... :O
-
Leo Dabus almost 4 yearsYou can warn them about this case being an exception :) As well as the reason why there is no need to call
super.didMoveToSuperview()
-
Leo Dabus almost 4 yearsThe text property being optional allows you to assign an optional string to it without the need to unwrap its value
-
FontFamily over 3 yearsWhile this solution may seem straightforward, there is actually a lot more code that is required to implement this. This answer isn't very helpful by itself and the addition of an explanation and inclusion of other relevant pieces of code might be helpful.
-
Silvering about 3 yearsBest answer. Thanks
-
deepOcean over 2 yearsWorked in my case, only digits in textfield
-
Peter Mortensen over 2 yearsIsn't something missing from the source code near "class MyViewController"? The syntax highlighting is off.
-
Peter Mortensen over 2 yearsThere is no one here by the name "Steven Schmatz". What answer does it refer to? Is it SwiftMatt's answer? The other three possibilities are "Alaeddine", "ZaEeM ZaFaR", and "Cloy" (deleted answer - link-only answer).
-
Peter Mortensen over 2 yearsThere is no one here by the name "Frouo". What answer does it refer to?
-
Peter Mortensen over 2 yearsWill that work?
MAX_LENGHT
looks like a misspelling. Why isn't itMAX_LENGTH
? Where is it defined? Dictionary: length -
Peter Mortensen over 2 yearsWhat is meant by the last sentence? Can you elaborate? What is not checked? What is only checked? For example, do you mean "Here I only checked for characters allowed in textField"? Please respond by editing (changing) your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).
-
TD540 over 2 yearsDefined nowhere :) I think his intention is for the reader of his comment to replace it with the wanted maximum length. Besides that, this answer should be the solution.