I'm practicing swiftui geometryEffect by applying it to a transition from view to another. The first view has three circles with different colors, the user selects a color by tapping the desired color, and clicks "next" to go to second view which contains a circle with the selected color.
GeometryEffect works fine when transitioning from FirstView
to SecondView
in which the selected circle's positions animates smoothly, but going back is the problem.
GeometryEffect does not animate the circle position smoothly when going back from SecondView
to FirstView
. Instead, it seems like it moves the circle to the left and right before positioning the circle to its original position.
Im sharing a GIF on my google drive to show what I mean:
I'd like to achieve something like this: desired result (file size is too large to be uploaded directly)
Thank you!
FirstView:
struct FirstView: View {
@Namespace var namespace
@State var whichStep: Int = 1
@State var selection: Int = 0
var colors: [Color] = [.red, .green, .blue]
@State var selectedColor = Color.black
var transitionNext: AnyTransition = .asymmetric(
insertion: .move(edge: .trailing),
removal:.move(edge: .leading))
var transitionBack: AnyTransition = .asymmetric(
insertion: .move(edge: .leading),
removal:.move(edge: .trailing))
@State var transition: AnyTransition = .asymmetric(
insertion: .move(edge: .trailing),
removal:.move(edge: .leading))
var body: some View {
VStack {
HStack { // back and next step buttons
Button { // back button
print("go back")
withAnimation(.spring()) {
whichStep = 1
transition = transitionBack
}
} label: {
Image(systemName: "arrow.backward")
.font(.system(size: 20))
}
.padding()
Spacer()
Button { // next button
withAnimation(.spring()) {
whichStep = 2
transition = transitionNext
}
} label: {
Text("next step")
}
}
Spacer()
if whichStep == 1 {
ScrollView {
ForEach(0..<colors.count, id:\.self) { color in
withAnimation(.none) {
Circle()
.fill(colors[color])
.frame(width: 100, height: 100)
.matchedGeometryEffect(id: color, in: namespace)
.onTapGesture {
selectedColor = colors[color]
selection = color
}
}
}
}
Spacer()
} else if whichStep == 2 {
// withAnimation(.spring()) {
ThirdView(showScreen: $whichStep, namespace: namespace, selection: $selection, color: selectedColor)
.transition(transition)
// }
Spacer()
}
}
.padding()
}
}
SecondView:
struct ThirdView: View {
var namespace: Namespace.ID
@Binding var selection: Int
@State var color: Color
var body: some View {
VStack {
GeometryReader { geo in
Circle()
.fill(color)
.frame(width: 100, height: 100)
.matchedGeometryEffect(id: selection, in: namespace)
}
}
.ignoresSafeArea()
}
}