Reputation: 2768
I'm trying to create a simple animation in SwiftUI and I would like the animation to start from center top and end to the center of the screen.
But, as you can see in the video, the animation starts from the top left corner when I use a NavigationView:
This is the code I am using for this example:
struct ContentView: View {
@State var show = false
var body: some View {
NavigationView {
HStack {
Text("Hello, world!")
.padding()
.background(Color.blue)
.offset(x: 0, y: show ? 0 : -30)
.animation(Animation.easeOut.delay(0.6))
.onAppear {
self.show = true
}
.navigationTitle("Why?")
}
}
}
}
Upvotes: 13
Views: 3006
Reputation: 258097
Why does an animation in a NavigationView starts from the top left corner?
Because implicit animation affects all animatable properties, including position, which on creation time is CGPoint.zero
(ie. top-left corner).
Such cases are solved by linking animation to dependent state value, thus it activates only when state changed, so all animatable properties not affected.
Here is possible variant for your case. Tested with Xcode 12.1 / iOS 14.1.
struct ContentView: View {
@State var show = false
var body: some View {
GeometryReader { gp in
NavigationView {
HStack {
Text("Hello, world!")
.padding()
.background(Color.blue)
.offset(x: 0, y: show ? 0 : -gp.size.height / 2)
.animation(Animation.easeOut.delay(0.6), value: show)
.onAppear {
self.show = true
}
.navigationTitle("Why?")
}
}
}
}
}
Upvotes: 6
Reputation: 4731
An easier solution in 5.6 for this is to use withAnimation:
struct ContentView: View {
@State var offset = 0.0
var body: some View {
NavigationView {
HStack {
Text("Hello, world!")
.padding()
.background(Color.blue)
.offset(x: 0, y: offset)
.onAppear {
withAnimation(Animation.easeOut) { offset -= 120 }
}
.navigationTitle("Why?")
}
}
}
}
Upvotes: 1
Reputation: 415
You can wrap self.show = true with DispatchQueue.main.async. Like this:
.onAppear {
DispatchQueue.main.async {
self.show = true
}
}
Upvotes: 4
Reputation: 2768
So the solution is to use the value parameter on the animation and it works:
struct ContentView: View {
@State var show = false
var body: some View {
NavigationView {
HStack {
Text("Hello, world!")
.padding()
.background(Color.blue)
.offset(x: 0, y: show ? 0 : -120)
.animation(Animation.easeOut.delay(0.6), value: show)
.onAppear {
self.show = true
}
.navigationTitle("Why?")
}
}
}
}
Upvotes: 2