Reputation: 999
I'm trying to animate a change to the overlay applied to a SwiftUI TextField. The state of the overlay is controlled by a state variable (simple boolean) and most references suggest that adding .animation() to the binding of this variable within the Toggle control should do the trick. However, it doesn't seem to have an effect. I've tried adding the same modifier to the view used for the overlay and wrapping the component views for the overlay in animation blocks - again, no joy.
Interestingly I have noted an error when running the code either in the canvas or the simulator which may well be significant:
2020-02-25 22:00:19.360009+0000 Sandbox[9392:671490] invalid mode 'kCFRunLoopCommonModes' provided to CFRunLoopRunSpecific - break on _CFRunLoopError_RunCalledWithInvalidMode to debug. This message will only appear once per execution.
The code is as follows (it's prototyping so a bit rough and ready). Can anyone tell me what I'm missing?
import SwiftUI
struct ContentView: View {
@State private var isValid = true
var body: some View {
VStack {
Form {
TextField("Placeholder", text: .constant(""))
.padding(6)
.background(ErrorView(isValid: $isValid)
.overlay(RoundedRectangle(cornerRadius: 4)
.stroke(Color(.systemGray3), lineWidth: 1))
.padding()
Toggle(isOn: $isValid.animation(.easeInOut), label: { Text("Toggle Valid") })
}
}
}
}
struct ErrorView: View {
@Binding var isValid: Bool
var body: some View {
if isValid {
return AnyView(EmptyView())
} else {
return AnyView(
ZStack {
HStack {
Spacer()
Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(Color.red)
.padding(.trailing, 8)
}
HStack {
Spacer()
Text("error message")
.font(.caption)
.foregroundColor(Color.red)
.offset(x: 0, y: -28)
}
}
)
}
}
}
Upvotes: 1
Views: 2482
Reputation: 257543
Here is possible approach, and a bit simplified, (tested & works with Xcode 11.2 / iOS 13.2)
struct ContentView: View {
@State private var isValid = true
var body: some View {
VStack {
Form {
TextField("Placeholder", text: .constant(""))
.padding(6)
.background(ErrorView().opacity(isValid ? 0.0 : 1.0))
.overlay(RoundedRectangle(cornerRadius: 4)
.stroke(Color(.systemGray3), lineWidth: 1))
.padding()
Toggle(isOn: $isValid.animation(), label: { Text("Toggle Valid") })
}
}
}
}
struct ErrorView: View {
var body: some View {
ZStack {
HStack {
Spacer()
Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(Color.red)
.padding(.trailing, 8)
}
HStack {
Spacer()
Text("error message")
.font(.caption)
.foregroundColor(Color.red)
.offset(x: 0, y: -28)
}
}
}
}
Upvotes: 2