Swiftui Animation and Subsequent Reverse Animation to Original State

SwiftUI animation and subsequent reverse animation to original state

Here is a solution based on ReversingScale animatable modifier, from this my answer

Update: Xcode 13.4 / iOS 15.5

demo

Complete test module is here

Tested with Xcode 11.4 / iOS 13.4

demo

struct DemoReverseAnimation: View {
@State var scalingFactor: CGFloat = 1

var body: some View {
Text("hello world")
.modifier(ReversingScale(to: scalingFactor, onEnded: {
DispatchQueue.main.async {
self.scalingFactor = 1
}
}))
.animation(.default)
.onAppear {
self.scalingFactor = 2
}
}
}

How can I reverse the slide transition for a SwiftUI animation?

@Asperi has already answered my question, but it didn't show up on google or stackoverflow when I searched for it, so here again for the algorithm:

How to reverse the slide transition in SwiftUI:

Taken from the Apple Developer Documentation:

static var slide: AnyTransition
// A transition that inserts by moving in from the leading edge, and removes by moving out towards the trailing edge.

Which can also be written as:

AnyTransition.asymmetric(
insertion: .move(edge: .leading),
removal: .move(edge: .trailing)
)

So to reverse the animation just flip insertion and removal and put that in your transition ViewModifier.

Since I needed to use it a few times I made an extension to AnyTransition so I can just call .transition(.backslide)

extension AnyTransition {
static var backslide: AnyTransition {
AnyTransition.asymmetric(
insertion: .move(edge: .trailing),
removal: .move(edge: .leading))}
}

How to animate a Text view in SwiftUI?

Appear/disappear is animated by container, so you need to place Text into some container and make it animatable, like

var body: some View {
VStack {

VStack {
if showingText {
Text("Hello world")
}
}.animation(.easeInOut, value: showingText) // << here !!

Button("Toggle") {
showingText.toggle()
}
}
}

SwiftUI how to have next and back animations?

You need to reverse transition when navigating back.

Here is possible approach (also made transition in one place and corrected animation to work everywhere, including Preview).

Tested with Xcode 12 / iOS 14.

demo

struct ContentView: View {
@State var page: Int = 0

@State private var isBack = false // << reverse flag (not animatable)
var body: some View {

VStack {
HStack {
Button(action: {
self.isBack = true
self.page = self.page - 1
}) {
Text("Back")
}

Spacer()

Button(action: {
self.isBack = false
self.page = self.page + 1
}) {
Text("Next")
}
}
Spacer()

Group {
if page == 0 {
PageView(name: "First page", color: .brown)
} else if page == 1 {
PageView(name: "Second page", color: .systemGreen)
} else if page == 2 {
PageView(name: "Third page", color: .systemBlue)
}
}.transition(AnyTransition.asymmetric(
insertion:.move(edge: isBack ? .leading : .trailing),
removal: .move(edge: isBack ? .trailing : .leading))
)
.animation(.default, value: self.page) // << animate here by value
}
}
}

SwiftUI prevent animation when updating State

I figured it out!

There is .animation(..., value: ...), where animation is only added to the view, if the value (which is an equatable), has changed. So the entire view is not affected by the animation, unless the state that defines the current view changes and transition begins.

A single component's animation is messing up the whole view — SwiftUI

You need to remove the animation(nil) in the AvatarComponent

You also need to change all .frame(width: 352) to .frame(width: UIScreen.main.bounds.size.width)



Related Topics



Leave a reply



Submit