Set the maximum character length of a UITextField in Swift
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
Max length UITextField
With Swift 5 and iOS 12, try the following implementation of textField(_:shouldChangeCharactersIn:replacementString:)
method that is part of the UITextFieldDelegate
protocol:
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 <= 10
}
- The most important part of this code is the conversion from
range
(NSRange
) torangeOfTextToReplace
(Range<String.Index>
). See this video tutorial to understand why this conversion is important. - To make this code work properly, you should also set the
textField
'ssmartInsertDeleteType
value toUITextSmartInsertDeleteType.no
. This will prevent the possible insertion of an (unwanted) extra space when performing a paste operation.
The complete sample code below shows how to implement textField(_:shouldChangeCharactersIn:replacementString:)
in a UIViewController
:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var textField: UITextField! // Link this to a UITextField in Storyboard
override func viewDidLoad() {
super.viewDidLoad()
textField.smartInsertDeleteType = UITextSmartInsertDeleteType.no
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 <= 10
}
}
Set the maximum character length of a UITextField
While the UITextField
class has no max length property, it's relatively simple to get this functionality by setting the text field's delegate
and implementing the following delegate method:
Objective-C
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Prevent crashing undo bug – see note below.
if(range.length + range.location > textField.text.length)
{
return NO;
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return newLength <= 25;
}
Swift
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentCharacterCount = textField.text?.count ?? 0
if range.length + range.location > currentCharacterCount {
return false
}
let newLength = currentCharacterCount + string.count - range.length
return newLength <= 25
}
Before the text field changes, the UITextField asks the delegate if the specified text should be changed. The text field has not changed at this point, so we grab it's current length and the string length we're inserting (either through pasting copied text or typing a single character using the keyboard), minus the range length. If this value is too long (more than 25 characters in this example), return NO
to prohibit the change.
When typing in a single character at the end of a text field, the range.location
will be the current field's length, and range.length
will be 0 because we're not replacing/deleting anything. Inserting into the middle of a text field just means a different range.location
, and pasting multiple characters just means string
has more than one character in it.
Deleting single characters or cutting multiple characters is specified by a range
with a non-zero length, and an empty string. Replacement is just a range deletion with a non-empty string.
A note on the crashing "undo" bug
As is mentioned in the comments, there is a bug with UITextField
that can lead to a crash.
If you paste in to the field, but the paste is prevented by your validation implementation, the paste operation is still recorded in the application's undo buffer. If you then fire an undo (by shaking the device and confirming an Undo), the UITextField
will attempt to replace the string it thinks it pasted in to itself with an empty string. This will crash because it never actually pasted the string in to itself. It will try to replace a part of the string that doesn't exist.
Fortunately you can protect the UITextField
from killing itself like this. You just need to ensure that the range it proposes to replace does exist within its current string. This is what the initial sanity check above does.
swift 3.0 with copy and paste working fine.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let str = (textView.text + text)
if str.characters.count <= 10 {
return true
}
textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
return false
}
Hope it's helpful to you.
UITextField setting maximum character length in Swift
You can subclass UITextField and add a target for UIControlEvents editingChanged. Inside the selector method you can use collection method prefix to limit the characters added to your textfield text property as follow:
import UIKit
class LimitedLengthField: UITextField {
var maxLength: Int = 10
override func willMove(toSuperview newSuperview: UIView?) {
addTarget(self, action: #selector(editingChanged), for: .editingChanged)
editingChanged()
}
@objc func editingChanged() {
text = String(text!.prefix(maxLength))
}
}
You can add your custom text field programatically or using the interface builder:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let limitedLenghtField = LimitedLengthField(frame: CGRect(origin: CGPoint(x: 50, y: 50), size: CGSize(width: 200, height: 50)))
limitedLenghtField.text = "123456789012345"
view.addSubview(limitedLenghtField)
}
}
Set UITextField Maximum Length
This works correctly with backspace and copy & paste:
#define MAXLENGTH 10
- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger oldLength = [textField.text length];
NSUInteger replacementLength = [string length];
NSUInteger rangeLength = range.length;
NSUInteger newLength = oldLength - rangeLength + replacementLength;
BOOL returnKey = [string rangeOfString: @"\n"].location != NSNotFound;
return newLength <= MAXLENGTH || returnKey;
}
UPDATE: Updated to accept the return key even when at MAXLENGTH. Thanks Mr Rogers!
Swift 4 UITextField max length in Alert
You actually don't need to create an instance of the UITextField
. The addTextField
closure will return the UITextField
for you. All you need to do is set the delegate of that text field in the closure.
class ViewController: UIViewController, UITextFieldDelegate {
let limitLength = 10
@IBOutlet weak var player1: UIButton!
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
let newLength = text.characters.count + string.characters.count - range.length
return newLength <= limitLength
}
@IBAction func player1Action(_ sender: UIButton) {
let alertController = UIAlertController(title: "Please enter you name", message: "Maximum 10 characters", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: {
alert -> Void in
let textField = alertController.textFields![0] as UITextField
self.player1.setTitle("\(textField.text!)", for: .normal)
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
alertController.addTextField(configurationHandler: {(textField : UITextField!) -> Void in
textField.placeholder = "Name"
textField.delegate = self // Set the delegate
})
present(alertController, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Create max character length in UITextField using IBInspectable
In Swift 5, String's prefix
method returns a value of type String.SubSequence
func prefix(_ maxLength: Int) -> Substring
You'll need to convert this to a String
type.
One way to do this might be:
let s = textField.text!.prefix(maxLength) // though UITextField.text is defined as an optional String, can be safely force-unwrapped as the default value is an empty string even when set to nil
textField.text = String(s)
or if you prefer a single-line solution:
textField.text = String(textField.text!.prefix(maxLength))
SwiftUI TextField max length
A slightly shorter version of Paulw11's answer would be:
class TextBindingManager: ObservableObject {
@Published var text = "" {
didSet {
if text.count > characterLimit && oldValue.count <= characterLimit {
text = oldValue
}
}
}
let characterLimit: Int
init(limit: Int = 5){
characterLimit = limit
}
}
struct ContentView: View {
@ObservedObject var textBindingManager = TextBindingManager(limit: 5)
var body: some View {
TextField("Placeholder", text: $textBindingManager.text)
}
}
All you need is an ObservableObject
wrapper for the TextField string. Think of it as an interpreter that gets notified every time there's a change and is able to send modifications back to the TextField. However, there's no need to create the PassthroughSubject
, using the @Published
modifier will have the same result, in less code.
One mention, you need to use didSet
, and not willSet
or you can end up in a recursive loop.
Related Topics
Resize Textfield Based on Content
Uipangesturerecognizer - Only Vertical or Horizontal
Check If Uicolor Is Dark or Bright
How Does Square's Cardcase App Automatically Populate the User's Details from the Address Book
Single Function to Dismiss All Open View Controllers
Programmatically Switching Between Tabs Within Swift
Detecting If iPhone Is in a Dark Room
Nib But Didn't Get a Uitableview
How to Convert a Nib-Based Project to a Storyboard-Based
How to Set Primary Key in Swift for Realm Model
Nsdateformatter Milliseconds Bug
Analysing Assets.Car File in iOS
How to Color a Uiimage in Swift
Localizing Strings in iOS: Default (Fallback) Language
Crashlytics in iOS Won't Proceed Past "Build Your Project" in Fabric App