1

I created a custom button in SwiftUi(ios) like this that has its own interaction but when I use it with two other animations, the interaction of the button is replaced by the new ones

Here is the custom button code


import SwiftUI

public struct fillCircular: ButtonStyle {

    var width: CGFloat
    var height: CGFloat = 50

    public func makeBody(configuration: Self.Configuration) -> some View {

        configuration.label
            .padding(.horizontal)
            .frame(width: width, height: height)
            .background(Capsule(style: .circular).fill(Color.primary))
            .font(.titleChanga3)
            .foregroundColor(Color.white)
            .shadow(color: Color.primary
                .opacity(configuration.isPressed ? 0.55 : 0.34),
                    radius: configuration.isPressed ? 1 : 4,
                    x: 0, y: configuration.isPressed ? 1 : 3)
            .scaleEffect(CGSize(width: configuration.isPressed ? 0.99 : 1,
                                height: configuration.isPressed ? 0.99 : 1))
            .animation(.spring())
    }
}

Here lies the problem

struct Welcome: View {

    @State var start: Bool = false

    var body: some View {
           GeometryReader { g in 
               Button(action: {}) {
                   Text("New Account")
               }
               .buttonStyle(fillCircular(width: g.size.width - (24 * 2)))
               .offset(y: self.start ? 0 : 20)
               .opacity(self.start ? 1 : 0)
               .animation(Animation.easeOut(duration: 0.5).delay(0.4))

          }

    }

When this method is added, the animation changes in the custom button (fillCircular)

.animation(Animation.easeOut(duration: 0.5).delay(0.4))

How do I enter Animation and at the same time maintain the interaction of the custom button

1 Answers1

0

Updated answer

Basically, your second .animation() call is overriding the first. Instead of applying the second animation, wrap your start = true in a withAnimation() call, like so:

struct WelcomeView: View {

    @State var start: Bool = false

    var body: some View {
        VStack {
            // This is just here to toggle start variable
            Button("Toggle", action: {
                withAnimation(Animation.easeOut(duration: 0.5).delay(0.4)) {
                    self.start.toggle()
                }
            })

            GeometryReader { g in
                Button(action: {}) {
                    Text("New Account")
                }
                .buttonStyle(fillCircular(width: g.size.width - (24 * 2)))
                .offset(y: self.start ? 0 : 20)
                .opacity(self.start ? 1 : 0)
            }
        }
    }
}

Then the easeOut animation will only apply when the button's action closure is called.

This answer is cleaner, but the original also works as of Swift 5.1 / Xcode 11.0

Original answer

Although it's a little hacky, you could have whatever sets start = true also set the animation to .spring() after a delay.

struct WelcomeView: View {

    @State var start: Bool = false
    @State var animation: Animation = Animation.easeOut(duration: 0.5).delay(0.4)

    var body: some View {
        VStack {
            // This is just here to toggle start variable
            Button("Toggle", action: {
                if !self.start {
                    // Show button, and after combined delay + duration, set animation to .spring()
                    self.start.toggle()
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
                        self.animation = .spring()
                    }
                } else {
                    // Set animation to .easeOut(), then hide button
                    self.animation = Animation.easeOut(duration: 0.5).delay(0.4)
                    self.start.toggle()
                }
            })

            GeometryReader { g in
                Button(action: {}) {
                    Text("New Account")
                }
                .buttonStyle(fillCircular(width: g.size.width - (24 * 2)))
                .offset(y: self.start ? 0 : 20)
                .opacity(self.start ? 1 : 0)
                .animation(self.animation)
            }
        }
    }
}
John M.
  • 8,892
  • 4
  • 31
  • 42