简体   繁体   中英

SwiftUI: attach an animation to a transition

According to the Apple documentation we should be able to attach an animation directly to a transition. For example:

.transition(AnyTransition.slide.animation(.linear))

documentation for the method:

extension AnyTransition {

    /// Attach an animation to this transition.
    public func animation(_ animation: Animation?) -> AnyTransition
}

says:

Summary

Attaches an animation to this transition.

But I can't manage to make it work. Take a look at this minimum viable example (you can copy-paste it and try yourself):

import SwiftUI

struct AnimationTest: View {
    @State private var show = false
    var body: some View {
        VStack {
            if show {
                Color.green
                    .transition(AnyTransition.slide.animation(.linear))
            } else {
                Color.yellow
                    .transition(AnyTransition.slide.animation(.linear))
            }
            Button(action: {
                self.show.toggle()
            }, label: {
                Text("CHANGE VIEW!")
            })
        }
    }
}

struct AnimationTest_Previews: PreviewProvider {
    static var previews: some View {
        AnimationTest()
    }
}

As you can see no animation happens at all. Any ideas? Thank you.

You need to wrap the boolean toggling within a withAnimation() closure:

withAnimation {
    self.show.toggle()
}

Tested the transition working on Xcode 11.2.1 while on the simulator ; the Canvas doesn't preview it.

Please note that animations/transitions applied directly to a view have an effect on that particular view and its children. Moreover, according to the docs:

func animation(Animation?) -> View

Applies the given animation to all animatable values within the view.

Since the animatable value, in this case the Bool toggle enabling the transition, is external to the Color views, it must be animated explicitly from where it's set in the button's action. Alternatively, one can effectively attach the transition directly to the target views, but apply the animation to their container, thus enabling interpolation of changes to show . So, this also achieves the desired result:

struct AnimationTest: View {
    @State private var show = false
    var body: some View {
        VStack {
            if show {
                Color.green
                    .transition(.slide)
            } else {
                Color.yellow
                    .transition(.slide)
            }
            Button(action: {
                self.show.toggle()
            }, label: {
                Text("CHANGE VIEW!")
            })
        }
        .animation(.linear)
    }
}

Those modifiers only specify kind of animation to be used during transition, but not activate them. You need to activate animation explicitly. In your case

withAnimation {
    self.show.toggle()
}

Note: transitions does not work in Preview, test on Simulator or real device.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM