Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI animation: Some implicit transition animations broken on iOS 13?

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.

enter image description here


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()
        }
    }
}

like image 204
Mike Bernardo Avatar asked Mar 31 '20 20:03

Mike Bernardo


People also ask

How do I add animations to SwiftUI?

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.

What is the default animation SwiftUI?

default is a basic animation with 0.35 seconds duration and an ease-in-ease-out timing curve.

What is withAnimation SwiftUI?

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.

How do I animate a view in SwiftUI?

If you want a SwiftUI view to start animating as soon as it appears, you should use the onAppear() modifier to attach an animation.

What is animation in SwiftUI?

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.

What is the difference between explicit and implicit animation in SwiftUI?

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.

What are the different types of transitions available in SwiftUI?

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.

Do opacity transitions work on SwiftUI?

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


2 Answers

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/

like image 52
Mike Bernardo Avatar answered Oct 19 '22 17:10

Mike Bernardo


To have implicit transitions animatable correctly it needs to make animatable container that includes these transitions.

Tested with Xcode 11.4 / iOS 13.4.

demo

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 !!
    }
}
like image 31
Asperi Avatar answered Oct 19 '22 19:10

Asperi