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.
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
}
}
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.
Limit TextField to x amount of characters using SwiftUI
U can use this:
.onReceive(variable.publisher.collect()) {
variable = String($0.prefix(4))
}
Code for textfield character limit isn't working(SwiftUI)
Your solution is lies in SwiftUI's subscriber .onReceive
,
Make sure that your property hasReachedLimit
must not marked with @Published
else it will trigger infinite loop of view body rendering.
Below shown code works as your expectation.
class TextLimiter: ObservableObject {
let limit: Int
@Published var value = ""
var hasReachedLimit = false
init(limit: Int) {
self.limit = limit
}
}
struct Strix: View {
@ObservedObject var input = TextLimiter(limit: 5)
var body: some View {
TextField("Text Input",
text: $input.value)
.border(Color.red,
width: $input.hasReachedLimit.wrappedValue ? 1 : 0 )
.onReceive(Just(self.input.value)) { inputValue in
self.input.hasReachedLimit = inputValue.count > self.input.limit
if inputValue.count > self.input.limit {
self.input.value.removeLast()
}
}
}
}
BTW this is not an efficient solution.
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)
}
}
}
}
Exceeding max Text() concatenation length - SwiftUI -
Hmm... unexpected limitation... anyway - learn something new.
Ok, here is improved algorithm, which should move that limitation far away.
Tested with Xcode 12 / iOS 14. (also updated code in referenced topic Highlight a specific part of the text in SwiftUI)
func hilightedText(str: String, searched: String) -> Text {
guard !str.isEmpty && !searched.isEmpty else { return Text(str) }
var result = Text("")
var range = str.startIndex..<str.endIndex
repeat {
guard let found = str.range(of: searched, options: .caseInsensitive, range: range, locale: nil) else {
result = result + Text(str[range])
break
}
let prefix = str[range.lowerBound..<found.lowerBound]
result = result + Text(prefix) + Text(str[found]).bold().foregroundColor(.yellow)
range = found.upperBound..<str.endIndex
} while (true)
return result
}
Related Topics
How to Get a Nsurl from an Xcassets Bundle
Removing Duplicates from Array of Custom Objects Swift
Xcode: "This App Could Not Be Installed at This Time."
Use a Generic Class as a Custom View in Interface Builder
Type 'Any' Has No Subscript Members (Firebase)
How to Disable/Remove Firebaseanalytics
How to Use Core Location/Gps Without Any Internet Connection/Disabled Cellular Network
What Is Sandbox in iOS? How to Transfer Data Between One App to Another App
How to Force a Hkquery to Load the Most Recent Steps Counts
Xcode - Bundle Format Unrecognized, Invalid, or Unsuitable
Swiftui Datepicker Binding Optional Date, Valid Nil
Unexpected Non-Void Return Value in Void Function Swift3
Core Data in Swift: Only Saving Last Object in a for Loop
iOS 5 JSON Parsing Results in Cocoa Error 3840