Tested on Xcode 11.3.1 and 11.4:
When attaching implicit animations to a transition, some transition types appear to be broken. Specifically, any position-related transitions do not apply the given implicit animation. .slide
, .move
, .offset
are broken. .opacity
and .scale
seem ok. (See attachment)
Explicit animations seem to work fine in all cases.
Even with custom compound Transitions, the position-related sub-transitions do not respond to implicit animation.
Is this a bug, or expected behavior?
Seems like this would be a problem if you want to trigger multiple different animation curves for specific UI elements based on an implicit property change.
struct MyExample: View {
@State private var isShowing = true
private let myAnimation = Animation.spring(response: 0.8, dampingFraction: 0.2, blendDuration: 3.0)
var body: some View {
VStack(spacing:20) {
if self.isShowing {
Text("Opacity").modifier(MyBigFont())
.transition(AnyTransition.opacity.animation(myAnimation))
Text("Scale").modifier(MyBigFont())
.transition(AnyTransition.scale.animation(myAnimation))
Text("Slide").modifier(MyBigFont())
.transition(AnyTransition.slide.animation(myAnimation))
Text("Move").modifier(MyBigFont())
.transition(AnyTransition.move(edge: .trailing).animation(myAnimation))
Text("Offset").modifier(MyBigFont())
.transition(AnyTransition.offset(x: 20, y: 0).animation(myAnimation))
Text("Custom").modifier(MyBigFont())
.transition(AnyTransition.myCustomTransition.animation(myAnimation))
}
Spacer()
Button(action: {
self.isShowing.toggle()
}) {
Text("Implicit Toggle")
}
Button(action: {
withAnimation(self.myAnimation) {
self.isShowing.toggle()
}
}) {
Text("Explicit Toggle")
}
}
}
}
struct MyBigFont: ViewModifier {
func body(content: Content) -> some View {
content
.lineLimit(1)
.padding()
.background(Color.purple)
.foregroundColor(.white)
.cornerRadius(8)
.font(Font.system(size: 21).bold())
}
}
struct MyCustomTransition: ViewModifier {
var isEnabled: Bool
func body(content: Content) -> some View {
if isEnabled {
return content
.offset(x: 20.0, y: 0.0)
.opacity(0)
} else {
return content
.offset(x: 0.0, y: 0.0)
.opacity(1)
}
}
}
extension AnyTransition {
static let myCustomTransition = AnyTransition.modifier(
active: MyCustomTransition(isEnabled: true),
identity: MyCustomTransition(isEnabled: false))
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
VStack {
MyExample()
Spacer()
}
}
}
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.
default is a basic animation with 0.35 seconds duration and an ease-in-ease-out timing curve.
withAnimation() takes a parameter specifying the kind of animation you want, so you could create a three-second linear animation like this: withAnimation(.linear(duration: 3)) Explicit animations are often helpful because they cause every affected view to animate, not just those that have implicit animations attached.
If you want a SwiftUI view to start animating as soon as it appears, you should use the onAppear() modifier to attach an animation.
SwiftUI Animation and Transitions This chapter is intended to provide an overview and examples of animating views and implementing transitions within a SwiftUI app. Animation can take a variety of forms including the rotation, scaling and motion of a view on the screen.
The difference between them is in explicit animation, we tell SwiftUI, this state variable will change depending on the animation, we're explicit with it, implicit animation is the opposite, somehow, SwiftUI won't know that state will depend on the animation, only after finding the .animation () modifier, then the animation will happen.
SwiftUI provides several options for animating these transitions including fading, scaling and sliding. SwiftUI also provides the ability to both combine transitions and define asymmetric transitions where different animation effects are used for insertion and removal of a view.
My findings are that opacity transitions don't always work. (yet a slide in combination with an .animation will work..) .transition (AnyTransition.opacity.animation (.easeInOut (duration: 0.2))) .zIndex (1) I can confirm this works. It's weird how some implementation on SwiftUI don't work consistently
According to Javier, implicit animations on transitions no longer work as of Xcode 11.2
If anyone has newer information, please reply.
Note that since XCode 11.2, transitions no longer work with implicit animations.
https://swiftui-lab.com/advanced-transitions/
To have implicit transitions animatable correctly it needs to make animatable container that includes these transitions.
Tested with Xcode 11.4 / iOS 13.4.
Here is the only fix made:
struct MyExample: View {
@State private var isShowing = true
private let myAnimation = Animation.spring(response: 0.8, dampingFraction: 0.2, blendDuration: 3.0)
var body: some View {
VStack(spacing:20) {
if self.isShowing {
... // all your code here
}
}.animation(myAnimation) // << fix !!
}
}
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