Animating gradient fill in swiftUI

So if anyone will be struggling with that my current solution is having two gradients in ZStack and animating opacity of the top one

Example gif

Here is rough example, the code sure can be written more nicely:

///helper extension to get some random Color
extension Color {
  static func random()->Color {
    let r = Double.random(in: 0 ... 1)
    let g = Double.random(in: 0 ... 1)
    let b = Double.random(in: 0 ... 1)
    return Color(red: r, green: g, blue: b)
  }
}

struct AnimatableGradientView: View {
  @State private var gradientA: [Color] = [.white, .red]
  @State private var gradientB: [Color] = [.white, .blue]

  @State private var firstPlane: Bool = true

  func setGradient(gradient: [Color]) {
    if firstPlane {
        gradientB = gradient
    }
    else {
        gradientA = gradient
    }
    firstPlane = !firstPlane
  }

  var body: some View {
    ZStack {
        Rectangle()
            .fill(LinearGradient(gradient: Gradient(colors: self.gradientA), startPoint: UnitPoint(x: 0, y: 0), endPoint: UnitPoint(x: 1, y: 1)))
        Rectangle()
            .fill(LinearGradient(gradient: Gradient(colors: self.gradientB), startPoint: UnitPoint(x: 0, y: 0), endPoint: UnitPoint(x: 1, y: 1)))
            .opacity(self.firstPlane ? 0 : 1)
        ///this button just demonstrates the solution
        Button(action:{
            withAnimation(.spring()) {
                self.setGradient(gradient: [Color.random(), Color.random()])
            }
        })
        {
            Text("Change gradient")
        }
    }
  }
}

Update: *In the end I have explored several ways of animating gradient fills and summarized them here: https://izakpavel.github.io/development/2019/09/30/animating-gradients-swiftui.html *

Tags:

Swiftui