swiftui

How to reveal a view with horizontal animation?


I'd like to reveal a view in the manner shown in the image below. I'd like the buttons within the capsule to fade in as the background shape animates outward to house the buttons. Possible? How? I've tried putting the buttons in an HStack and doing something like .animation(.spring(response: 0.4, dampingFraction: 0.75), value: animating) but I can't get the effect working. I'd like to reverse the animation when a button is pressed so that the capsule closes and the buttons fade out.

if showPetOptions {
    PetOptionsView()
        .transition(???)
}

enter image description here


Solution

  • Similar to my answer here, you can write a custom transition, that animates a mask of the view, using a scaleEffect.

    struct RevealTransition: Transition {
        func body(content: Content, phase: TransitionPhase) -> some View {
            content.mask {
                Rectangle()
                    .scaleEffect(x: phase.isIdentity ? 1 : 0)
            }
        }
    }
    
    extension AnyTransition {
        static var reveal: AnyTransition { AnyTransition(RevealTransition()) }
    }
    
    @State private var showPetOptions = false
    
    var body: some View {
        VStack {
            Button("Toggle") {
                withAnimation(/* insert your favourite animation here*/) {
                    showPetOptions.toggle()
                }
            }
    
            if showPetOptions {
                HStack {
                    Button("Dog") { }
                    Button("Cat") { }
                }
                .padding(4)
                .background(.gray, in: .capsule)
                .transition(.reveal) // <--------------
            }
        }
        .padding()
    }