Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animating gradient fill in swiftUI

Tags:

swiftui

Having rectangle with gradient fill and trying to animate color change.

...
  Rectangle()
    .fill(LinearGradient(
          gradient: .init(stops: [Gradient.Stop(color: myColor, location: 0.0), Gradient.Stop(color: .blue, location: 1.0)]),
          startPoint: .init(x: 0.5, y: startPoint),
          endPoint: .init(x: 0.5, y: 1-startPoint)
          ))
     .animation(Animation.easeIn(duration: 2))
...

While change of starting points is animated nicely; the color change is not animated at all and just "switches"

Any hints?

like image 845
Pavel Zak Avatar asked Aug 20 '19 15:08

Pavel Zak


People also ask

How do you fill an animated gradient?

Select the Gradient Transform tool from the Tools panel. If you do not see the Gradient Transform tool in the Tools panel, click and hold on the Free Transform tool and then select the Gradient Transform tool from the menu that appears. Click an area filled with a gradient or bitmap fill.

How do I change gradient color in SwiftUI?

Initializing Colors SwiftUI provides with multiple ways to initialize colors. One way to do it is using Color(red: ..., green: ..., blue: ...) . You can provide the RGB (Red, Green, blue) value on a 0-1 range. You can also initialize color with UIColor (from UIKit) and NSColor (from AppKit).

Can we animate linear gradient?

Thanks to the new @property defined in the CSS Properties and Values API Level 1 specification we can now have transition with custom properties (aka CSS variables).

How do I make an animation in SwiftUI?

SwiftUI has built-in support for animations with its animation() modifier. To use this modifier, place it after any other modifiers for your views, tell it what kind of animation you want, and also make sure you attach it to a particular value so the animation triggers only when that specific value changes.


1 Answers

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 *

like image 178
Pavel Zak Avatar answered Jan 06 '23 16:01

Pavel Zak