【问题标题】:How can I create an animation color change from center of a view in SwiftUI?如何在 SwiftUI 中从视图中心创建动画颜色变化?
【发布时间】:2021-04-13 16:30:54
【问题描述】:

如何在 SwiftUI 中从视图中心创建动画颜色变化? (请看下面的gif)?

到目前为止,我已经尝试向视图添加动画修改器(请参见下面的代码),但不太确定如何使动画从屏幕中心开始并流到屏幕的外边缘。

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

【问题讨论】:

标签: swift xcode swiftui


【解决方案1】:

您可以在ZStack 中使用两个Circles,并为最顶部的圆圈的缩放效果值设置动画。

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]
    }
}

【讨论】:

    【解决方案2】:

    这样做可能有更优雅的方式,但它确实有效。

    struct AnimatedBackground: View {
        @State var circleColor = Color.red
        @State var height:CGFloat = 0
        @State var backgroundColor: Color = .clear
        @State var animation: Animation? = .default
        var body: some View {
            ZStack{
                backgroundColor.ignoresSafeArea()
                Circle()
                    .foregroundColor(circleColor)
                    .scaleEffect(CGSize(width: height, height: height))
                
                
                VStack {
                    Button(action: {
                        animation = .default
                        circleColor = [Color.red, Color.orange, Color.green, Color.black, Color.gray, Color.white].randomElement()!
                    }, label: {
                        
                        Text("change background color")
                    })
                    
                }
            }.animation(animation)
            .onChange(of: circleColor, perform: { value in
                
                Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: {timer in
                    height += 0.2
                    if height >= 3{
                        animation = nil
                        backgroundColor = circleColor
                        
                        height = 0
                        timer.invalidate()
                        
                    }
                })
            })
        }
        
    }
    

    【讨论】:

      猜你喜欢
      • 2021-07-08
      • 2021-09-29
      • 1970-01-01
      • 2013-08-15
      • 1970-01-01
      • 2011-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多