SwiftUI has wonderful animation features, but the way it handles changes in Text
View content is problematic. It animates the change of the text frame but changes the text immediately without animation. As a result, when the content of a Text
View is made longer, animating the transition causes an ellipsis (…) to appear until the text frame reaches its full width. For example, in this little app, pressing the Toggle button switches between shorter and longer text:
Here's the code:
import SwiftUI
struct ContentView: View {
@State var shortString = true
var body: some View {
VStack {
Text(shortString ? "This is short." : "This is considerably longer.").font(.title)
.animation(.easeInOut(duration:1.0))
Button(action: {self.shortString.toggle()}) {
Text("Toggle").padding()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The question is: how to avoid the ellipsis? When animating a one character string into a two character string the situation is even worse, because the short string is completely replaced by the ellipsis while it animates into the longer string.
One possibility is to assign a separate id to the view in one state or another by adding the modifier, for instance, .id(self.shortString ? 0 : 1)
and then adding a .transition()
modifier. That will treat the Text as two different Views, before and after. Unfortunately, in my case I need to move text location during the change, and different ids makes animating that impossible.
I guess the solution is a creative use of AnimatableData
. Any ideas?
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.
Text is displayed in SwiftUI using the Text view. The text can be configured in a number of ways using modifiers such as font, fontweight, padding and background. The default Text can handle multiline text and it can be modified to set how many lines to display or how to truncate the text.
If you add .animation(nil)
to the Text object definition then the contents will change directly between values, avoiding ellipsis.
However, this may prevent the animation of the text location, which you also mention wanting to do simultaneously.
Here is a demo of possible approach (scratchy - you can redesign it to extension, modifier, or separate view)
Tested with Xcode 11.4 / iOS 13.4
struct ContentView: View {
@State var shortString = true
var body: some View {
VStack {
if shortString {
Text("This is short.").font(.title).fixedSize()
.transition(AnyTransition.opacity.animation(.easeInOut(duration:1.0)))
}
if !shortString {
Text("This is considerably longer.").font(.title).fixedSize()
.transition(AnyTransition.opacity.animation(.easeInOut(duration:1.0)))
}
Button(action: {self.shortString.toggle()}) {
Text("Toggle").padding()
}
}
}
}
Any suggestions for shrinking an animated gif's dimensions?
I use this way:
- decrease zoom of Preview to 75% (or resize window of Simulator)
- use QuickTimePlayer region-based Screen Recording
- use https://ezgif.com/video-to-gif for converting to GIF
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