How to detect live changes on TextField in SwiftUI?
You can create a binding with a custom closure, like this:
struct ContentView: View {
@State var location: String = ""
var body: some View {
let binding = Binding<String>(get: {
self.location
}, set: {
self.location = $0
// do whatever you want here
})
return VStack {
Text("Current location: \(location)")
TextField("Search Location", text: binding)
}
}
}
How to detect when a TextField becomes active in SwiftUI?
The answer is to initialize TextField with the onEditingChanged parameter.
We can then execute a closure conditionally depending upon whether the text field was edited or changes were committed:
TextField("", text: $email, onEditingChanged: { changed in
if changed {
// User began editing the text field
}
else {
// User tapped the return key
}
})
Observe changes on SwiftUI TextField
A simple custom binding
is a good start for this task:
struct ContentView: View {
@State private var query = ""
var body: some View {
let binding = Binding<String>(
get: { self.query },
set: { self.query = $0; self.textFieldChanged($0) }
)
return NavigationView {
List {
TextField("Text", text: binding)
}
}
}
private func textFieldChanged(_ text: String) { print(text) }
}
It is tested and working
SwiftUI - detect change in Textfield
here is a simple example that maybe of use to you, using some of the comments advice. There are 3 main elements, the condition, the disabling and the color.
struct ContentView: View {
@State private var password = ""
@State private var passwordRepeat = ""
// here the condition you want
var isConfirmed: Bool {
if !password.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
!passwordRepeat.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
(password == passwordRepeat) {
return true
} else {
return false
}
}
var body: some View {
VStack {
SecureField("password", text: $password)
SecureField("password confirm", text: $passwordRepeat)
Button(action: { } ) {
Text("SAVE").accentColor(.white)
}
.disabled(!isConfirmed) // <-- here to enable/disable the button
.padding(20)
.background(isConfirmed ? Color.green : Color.gray) // <-- here to change color of the button
.cornerRadius(20)
}.frame(width: 333)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
EDIT1:
here is an approach to make the condition work with when your Textfield already has content in it:
// your ProfileEditorRow equivalent
struct ContentView: View {
@ObservedObject var profileViewModel: ProfileViewModel
let refUserName: String // <-- reference user name
init(profileViewModel: ProfileViewModel) {
self.profileViewModel = profileViewModel
self.refUserName = profileViewModel.user.name // <-- here keep the initial user name
}
var isCondition: Bool {
return (refUserName == profileViewModel.name) // <-- here test for change
}
var body: some View {
VStack {
TextField("test",text: $profileViewModel.user.name)
Button(action: { print("----> SAVE") } ) {
Text("SAVE").accentColor(.white)
}
.disabled(isCondition) // <-- here to enable/disable the button
.padding(20)
.background(isCondition ? Color.gray : Color.green) // <-- here to change color of the button
.cornerRadius(20)
}.frame(width: 333)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
EDIT2: sample with multiple elements in condition
You probably have a User
struct with name, birthday etc... using this:
struct User {
var name
var birthday
var gender
// ....
}
struct ContentView: View {
@ObservedObject var profileViewModel: ProfileViewModel
let refUser: User // <-- reference user
init(profileViewModel: ProfileViewModel) {
self.profileViewModel = profileViewModel
self.refUser = profileViewModel.user // <-- here keep the initial user values
}
var isCondition: Bool {
return (refUser.name == profileViewModel.user.name) &&
(refUser.birthday == profileViewModel.user.birthday)
}
var body: some View {
VStack {
TextField("name",text: $profileViewModel.user.name)
TextField("birthday",text: $profileViewModel.user.birthday)
Button(action: { print("----> SAVE") } ) {
Text("SAVE").accentColor(.white)
}
.disabled(isCondition) // <-- here to enable/disable the button
.padding(20)
.background(isCondition ? Color.gray : Color.green) // <-- here to change color of the button
.cornerRadius(20)
}.frame(width: 333)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
Swiftui Textfield not updating when value changes
The answer is simply that TextFields
don't update while they are in focus. To solve this problem, you need to incorporate a @FocusState
in to the view, and cause the TextField
to lose focus right before updating the variable. You can test it in your own view by tapping your Text
prior to tapping in to the TextField
. You will see it updates just fine.
struct ButtonUpdateTextField: View {
@State private var amount: Double = 0.0
@FocusState var isFocused: Bool // <-- add here
var body: some View {
Form {
VStack {
HStack {
Text("Amount EUR")
Spacer()
TextField("Type amount", value: $amount, format: .number)
.keyboardType(.numberPad)
.multilineTextAlignment(.trailing)
.focused($isFocused) // <-- add here
}
Text("Set MAX (999)")
.frame(maxWidth: .infinity, alignment: .leading)
.onTapGesture {
print("before tap \(amount )")
isFocused = false // <-- add here
amount = 999
print("after tap \(amount)")
}
}
}
}
}
How to determine which Textfield is being changed in SwiftUI
Just use different functions as callbacks, like
TextField("", text: $phoneAuthViewModel.firstCodeField)
.onChange(of: phoneAuthViewModel.firstCodeField, perform: codeChanged(_:))
TextField("", text: $phoneAuthViewModel.country)
.onChange(of: phoneAuthViewModel.country, perform: countryChanged(_:))
func codeChanged(_ value: String) {
// handle code changed here
}
func countryChanged(_ value: String) {
// handle country changed here
}
Check Number of Characters Of Textfield in SwiftUI
You can use .onChange :
.onChange(of: name) { newValue in
if newValue.count >= 3 {
// Call function
}
}
Change value of Text while typing in TextField at a time without clicking anywhere - SwiftUI
SwiftUI is not like Cocoa. It is not event-driven, and there is no communication from one interface object to another. There is only data. Data flows thru state variables. It flows up by a state variable's binding and down by a state variable's value.
So you don't need an onEditingChanged
event, or any other event. $totalAmount
is a binding. It changes when the text field's text changes, automatically.
Moreover, totalAmount
is a state variable. If the Text uses this as its value, directly or indirectly, the text changes automatically when totalAmount
changes.
So just use a calculated variable that depends on totalAmount
and make that the value of the Text and you're done.
Extremely basic example:
struct ContentView : View {
@State var totalAmount = ""
let addAmount = 10.0 // or whatever
var calc : Double { (Double(totalAmount) ?? 0.0) + addAmount } // or whatever
var body: some View {
HStack {
TextField("Type a number", text: $totalAmount)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(width:100)
Text(String(self.calc))
}
}
}
Related Topics
Uicollectionview Select and Deselect Issue
Don't Launch Simulator When Running Unittests
Get Selected Index of Uitableview
Repeating Local Notifications for Specific Days of Week (Swift 3 iOS 10)
How to Convert an iPhone Osstatus Code to Something Useful
Remembering Scroll Position on Uitableview
Swift "Bridging-Header.H" File Not Allowing Me to Instantiate Objective-C Classes in .Swift Files
Does Non-Renewing Subscription Requires a Restore Button
Facebooksdk and Bolts Conflicting Each Other (Duplicate Symbols) on Build
How Does Google's Custom iOS Keyboard, Gboard, Programmatically Dismiss the Frontmost App
This Certificate Was Signed by an Unknown Authority
Removing from Array During Enumeration in Swift
Calculating Tiles to Display in a Maprect When "Over-Zoomed" Beyond the Overlay Tile Set
Xcode Is Creating Generic Xcode Archive Instead of iOS App Archive
Convert String to Date Type in Swift 3
What Exactly Are Protocols and Delegates and How Are They Used in iOS