Question is simple: how in the world do i get a Text
to animate properly?
struct ContentView: View {
@State var foozle: String = ""
var body: some View {
VStack() {
Spacer()
Text(self.foozle)
.frame(maxWidth: .infinity)
.transition(.opacity)
Button(action: {
withAnimation(.easeInOut(duration: 2)) {
self.foozle = "uuuuuuuuu"
}
}) { Text("ugh") }
Spacer()
}.frame(width: 320, height: 240)
}
}
The problem: the view insists on doing some dumb animation where the text is replaced with the new text, but truncated with ellipses, and it slowly expands widthwise until the entirety of the new text is shown.
Naturally, this is not an animation on opacity. It's not a frame width problem, as I've verified with drawing the borders.
Is this just another dumb bug in SwiftUI that i'm going to have to deal with, and pray that someone fixes it?
EDIT: ok, so thanks to @Mac3n, i got this inspiration, which works correctly, even if it's a little ugly:
Text(self.foozle)
.frame(maxWidth: .infinity)
.opacity(op)
Button(action: {
withAnimation(.easeOut(duration: 0.3)) {
self.op = 0
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.foozle += "omo"
withAnimation(.easeIn(duration: 0.3)) {
self.op = 1
}
}
}
}) {
Text("ugh")
}
transparency is called the alpha property in animate (with an alpha = 0 being transparent and an alpha =1 being fully opaque). Absolutely.
SwiftUI has built-in support for animations with its animation() modifier. To use this modifier, place it after any other modifiers for your views, tell it what kind of animation you want, and also make sure you attach it to a particular value so the animation triggers only when that specific value changes.
The problem is that SwiftUI sees Text view as the same view. You can use the .id() method on the view to set it. In this case I've just set the value to a hash of the text itself, so if you change the text, the entire view will get replaced.
struct ContentView: View {
@State var foozle: String = ""
var body: some View {
VStack() {
Spacer()
Text(self.foozle)
.id(self.foozle.hashValue)
.frame(maxWidth: .infinity)
.transition(.opacity)
Button(action: {
withAnimation(.easeInOut(duration: 2)) {
self.foozle = "uuuuuuuuu"
}
}) { Text("ugh") }
Spacer()
}.frame(width: 320, height: 240)
}
}
Transition
works when view appeared/disappeared. In your use-case there is no such workflow.
Here is a demo of possible approach to hide/unhide text with opacity animation:
struct DemoTextOpacity: View {
var foozle: String = "uuuuuuuuu"
@State private var hidden = true
var body: some View {
VStack() {
Spacer()
Text(self.foozle)
.frame(maxWidth: .infinity)
.opacity(hidden ? 0 : 1)
Button(action: {
withAnimation(.easeInOut(duration: 2)) {
self.hidden.toggle()
}
}) { Text("ugh") }
Spacer()
}.frame(width: 320, height: 240)
}
}
If you want to animate on opacity you need to change opacity value on your text element.
code example:
@State private var textValue: String = "Sample Data"
@State private var opacity: Double = 1
var body: some View {
VStack{
Text("\(textValue)")
.opacity(opacity)
Button("Next") {
withAnimation(.easeInOut(duration: 0.5), {
self.opacity = 0
})
self.textValue = "uuuuuuuuuuuuuuu"
withAnimation(.easeInOut(duration: 1), {
self.opacity = 1
})
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With