swiftUI geometryEffect animation

257 Views Asked by At

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: enter image description here

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

}

0

There are 0 best solutions below