Home > Software design >  SwiftUI: How to create a custom SwiftUI Transition depending on a State Object?
SwiftUI: How to create a custom SwiftUI Transition depending on a State Object?

Time:05-17

Context: I have encountered a problem while working with SwiftUI Transitions. I have a FormView containing 4 different Sub-Forms. When the User presses the Next-Button, the next Sub-Form View is presented with a Transition (.move -> right to left).

I also have a Back Button. When the User presses this Button, the previous Sub-Form View is shown, currently with the same Transition (.move -> right to left). However, I'd like to reverse the Transition in this case to (.move -> left to right).


Code

enum FormStep {
    case step1, step2, step3, step4
}

struct CustomForm: View  {
    @State private var step: FormStep = .step1

    var body: some View {
        // This Button will change the step State to the previous step
        Button(action: { withAnimation { previousStep() } } { Text("Previous") }

        // This is the Right to Left Transition applied to subForm
        subForm
            .transition(.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)))

        // This Button will change the step State to the next step
        Button(action: { withAnimation { nextStep() } } { Text("Next") }
    }

    @ViewBuilder private var subForm: some View {
        switch medicationFormVM.step {
        case .step1: StepOneSubForm()
        case .step2: StepTwoSubForm()
        case .step3: StepThreeSubForm()
        case .step4: StepFourSubForm()
        }
    }
}

Question: As you can see, not matter whether you navigate back or forth, the Transition will always be right to left. How can I achieve my goal of changing the Transition depending on which Button got pressed?

CodePudding user response:

Here is an approach for you:

enum FormTransition {
    case next, back
    var value: AnyTransition {
        switch self {
        case .next:
            return AnyTransition.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading))
        case .back:
            return AnyTransition.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .trailing))
        }
    }
}

struct CustomForm: View  {
    
    @State private var step: FormStep = .step1
    @State private var transition: AnyTransition = FormTransition.next.value
    
    var body: some View {
        
        Button(action: { transition = FormTransition.back.value; withAnimation { previousStep() } } { Text("Previous") })
        
        subForm
            .transition(transition)
        
        Button(action: { transition = FormTransition.next.value; withAnimation { nextStep() } } { Text("Next") })
    }
    
}
  • Related