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.
Is it possible to set a character limit on a TextField using SwiftUI?
Here is one way, not sure if it was mentioned in the other examples you gave:
@State var text = ""
var body: some View {
TextField("text", text: $text)
.onReceive(text.publisher.collect()) {
self.text = String($0.prefix(5))
}
}
The text.publisher
will publish each character as it is typed. Collect them into an array and then just take the prefix.
How to set textfield character limit SwiftUI?
No need to use didSet on your published property. You can add a modifier to TextField and limit the string value to its prefix limited to the character limit:
import SwiftUI
struct ContentView: View {
@ObservedObject var textBindingManager = TextBindingManager(limit: 5)
var body: some View {
TextField("Placeholder", text: $textBindingManager.phoneNumber)
.padding()
.onChange(of: textBindingManager.phoneNumber, perform: editingChanged)
}
func editingChanged(_ value: String) {
textBindingManager.phoneNumber = String(value.prefix(textBindingManager.characterLimit))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
class TextBindingManager: ObservableObject {
let characterLimit: Int
@Published var phoneNumber = ""
init(limit: Int = 10){
characterLimit = limit
}
}
Limit TextField to x amount of characters using SwiftUI
U can use this:
.onReceive(variable.publisher.collect()) {
variable = String($0.prefix(4))
}
How to limit the number of characters while also allowing only a subset of characters in a TextField?
You can simply filter all characters that is whole number and get the first 10 characters of the resulting string. You would need also to check if the string is empty and set the value back to zero:
import SwiftUI
import Combine
struct ContentView: View {
@State private var text = "0"
let maxLength = 10
var body: some View {
TextField("", text: $text)
.keyboardType(.numberPad)
.onReceive(Just(text)) {
guard !$0.isEmpty else {
self.text = "0"
return
}
if let value = Int($0.filter(\.isWholeNumber).prefix(maxLength)) {
self.text = String(value)
}
}
}
}
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
Switching to next UITextField when character limit is reached
You could use the delegate method for UITextField
shouldChangeCharactersInRange
. You'd have to do a little setup work though. Here's an example that creates 3 textFields, conforms to the UITextFieldDelegate
, and does something similar to what you're describing.
class ViewController: UIViewController, UITextFieldDelegate {
var max = 3
var fields:[UITextField] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// This is just an example to layout 3 text fields.
for i in 0 ..< 3 {
let field = UITextField()
view.addSubview(field)
field.delegate = self
field.borderStyle = .roundedRect
field.font = UIFont(name: "AvenirNext-Regular", size: 15.0)
field.textColor = UIColor.black
field.frame = CGRect(x: view.bounds.width/2 - 100, y: 100 + (150*CGFloat(i)), width: 200, height: 50)
fields.append(field)
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Make sure the field has non-nil text
if let text = textField.text {
// Check if the text length has reached max limit
if text.characters.count > (max-1) {
// Get index of field from fields array
if let index = fields.index(of: textField) {
// Make sure it's not the last field in the array else return false
if index < fields.count-1 {
// Make the next field in the array become first responder if it's text is non-nil and it's text's character count is less than desired max
if fields[index+1].text != nil && fields[index+1].text!.characters.count < (max-1) {
fields[index+1].becomeFirstResponder()
} else {
return false
}
} else {
return false
}
}
}
}
return true
}
}
Setting maximum number of characters of `UITextView ` and `UITextField `
Update Swift 4.X
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
let numberOfChars = newText.count
return numberOfChars < 10 // 10 Limit Value
}
Try this out:
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
let numberOfChars = newText.characters.count // for Swift use count(newText)
return numberOfChars < 10;
}
How to create TextField that only accepts numbers
tl;dr
Checkout John M's solution for a much better way.
One way to do it is that you can set the type of keyboard on the TextField
which will limit what people can type on.
TextField("Total number of people", text: $numOfPeople)
.keyboardType(.numberPad)
Apple's documentation can be found here, and you can see a list of all supported keyboard types here.
However, this method is only a first step and is not ideal as the only solution:
- iPad doesn't have a numberPad so this method won't work on an iPad.
- If the user is using a hardware keyboard then this method won't work.
- It does not check what the user has entered. A user could copy/paste a non-numeric value into the TextField.
You should sanitise the data that is entered and make sure that it is purely numeric.
For a solution that does that checkout John M's solution below. He does a great job explaining how to sanitise the data and how it works.
Related Topics
Swift Programmatically Create Function for Button with a Closure
Sort Dictionary Keys by Value, Then by Key
How to Refresh Multiple Timers in Widget iOS14
How to Make a Custom Mkannotationview with Xib
Scrolling Delegate in Tableview
Swift: How to Fix Infinite Loop When Adding a Value to a Firebase Variable
Swift Calculate Time for Timers Running in Background
How to Pass a Nil Value for One of the Parameter in Alamofire Post Request
Swift Associated Types and Protocol Inheritance
Navigationlink Is Grayed Out and Does Not Perform Any Action
Swift 4.2 - _Shared Attribute Near Type
Swift Error Using Initialized Properties in Expressions Before Super.Init
Swift Spritekit I Detect a Collison But It Reads the Collision Mulitple Times
Value of Type 'Tags' Has No Member 'Lastused'
Inline Kvo of a Property in Another View Controller
Differences Generic Protocol Type Parameter VS Direct Protocol Type
Delegate Must Respond to Locationmanager:Didupdatelocations Swift Eroor