Nighthawk
Nighthawk

Reputation: 992

How can I create an animation color change from center of a view in SwiftUI?

How can I create an animation color change from center of a view in SwiftUI? (please see the below gif)?

enter image description here

So far I have tried adding an animation modifier to the view (please see the below code), but am not quite sure how to make the animation start at the center of the screen and flow to the outer edges of the screen.

import SwiftUI

struct ContentView: View {
    @State var color = Color.red

var body: some View {
    VStack {
        Button(action: {
            color = .green
        }, label: {
            
            Text("change background color")
        })
        
    }
    .frame(maxWidth: .infinity)
    .frame(maxHeight: .infinity)
    .background(color)
    .animation(.default)
    
}
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
} 

Upvotes: 0

Views: 1293

Answers (1)

Cuneyt
Cuneyt

Reputation: 981

You can use two Circles in a ZStack and animate the scale effect value of the top most circle.

struct ContentView: View {

    private let colors: [Color] = [.red, .yellow, .blue, .pink, .orange]
    private let maxScaleEffect: CGFloat = 4.0
    private let minScaleEffect: CGFloat = 0
    private let animationDuration = 0.6
    private let animationDelay = 0.1

    @State private var shouldTransition = true
    @State private var colorIndex = 0

    var body: some View {
        ZStack {
            Circle()
                .fill(previousColor)
                .scaleEffect(maxScaleEffect)

            Circle()
                .fill(transitioningColor)
                .scaleEffect(shouldTransition ? maxScaleEffect : minScaleEffect)

            Button("Change color") {
                shouldTransition = false
                colorIndex += 1

                // Removing DispatchQueue here will cause the first transition not to work
                DispatchQueue.main.asyncAfter(deadline: .now() + animationDelay) {
                    withAnimation(.easeInOut(duration: animationDuration)) {
                        shouldTransition = true
                    }
                }
            }
            .foregroundColor(.primary)
        }
    }

    private var previousColor: Color {
        colors[colorIndex%colors.count]
    }

    private var transitioningColor: Color {
        colors[(colorIndex+1)%colors.count]
    }
}

Upvotes: 3

Related Questions