So I have a linear gradient view and I have the colors animating with the .animation()
modifier. Right now, the colors swirl back and forth as I adjust the start
and end
points of the gradient and use an .easeInAndOut()
modifier to animate. I want the colors to swirl in one direction, clockwise, repeatedly, but instead it swirls back and forth.
struct AnimatedBackground: View {
@State var start = UnitPoint.leading
@State var end = UnitPoint.trailing
let timer = Timer.publish(every: 1, on: .main, in: .default).autoconnect()
let colors: [Color] = [ .blue, .red ]
var body: some View {
LinearGradient(gradient: Gradient(colors: colors), startPoint: start, endPoint: end)
.animation(Animation.easeInOut(duration: 3).repeatForever())
.onReceive(timer, perform: { _ in
self.start = .topLeading
self.end = .bottomTrailing
self.start = .bottom
self.end = .top
self.start = .bottomLeading
self.end = .topTrailing
self.start = .leading
self.end = .trailing
self.start = .topLeading
self.end = .bottomTrailing
self.start = .top
self.end = .bottom
self.start = .bottomLeading
self.end = .topTrailing
self.start = .leading
self.end = .trailing
}).edgesIgnoringSafeArea(.all)
}
}
The gradient colors swirl back and forth . I want the colors to swirl in one clockwise direction, smoothly and repeatedly.
Let's debug! First, before and after your huge sequence of self.start = ...
, try adding print
statements.
print("Before: \(start), \(end)")
self.start = .topLeading
self.end = .bottomTrailing
self.start = .bottom
self.end = .top
self.start = .bottomLeading
self.end = .topTrailing
self.start = .leading
self.end = .trailing
self.start = .topLeading
self.end = .bottomTrailing
self.start = .top
self.end = .bottom
self.start = .bottomLeading
self.end = .topTrailing
self.start = .leading
self.end = .trailing
print("After: \(start), \(end)")
You'll notice that both print
s happen at pretty much the exact same time.
Before: UnitPoint(x: 0.0, y: 0.5), UnitPoint(x: 1.0, y: 0.5)
After: UnitPoint(x: 0.0, y: 0.5), UnitPoint(x: 1.0, y: 0.5)
This is because Swift code executes instantly, one line after another in an extremely small amount of time. As a result, start
always becomes (x: 0.0, y: 0.5)
( .leading
), and end
always becomes (x: 1.0, y: 0.5)
( .trailing
). Your gradient probably doesn't even animate at all!
To fix, you should simply get the current value of start
and end
, then manually calculate the next value.
struct AnimatedBackground: View {
@State var start = UnitPoint.leading
@State var end = UnitPoint.trailing
let timer = Timer.publish(every: 1, on: .main, in: .default).autoconnect()
let colors: [Color] = [.blue, .red]
var body: some View {
LinearGradient(gradient: Gradient(colors: colors), startPoint: start, endPoint: end)
.animation(Animation.easeInOut(duration: 3).repeatForever(), value: start) /// don't forget the `value`!
.onReceive(timer) { _ in
self.start = nextPointFrom(self.start)
self.end = nextPointFrom(self.end)
}
.edgesIgnoringSafeArea(.all)
}
/// cycle to the next point
func nextPointFrom(_ currentPoint: UnitPoint) -> UnitPoint {
switch currentPoint {
case .top:
return .topLeading
case .topLeading:
return .leading
case .leading:
return .bottomLeading
case .bottomLeading:
return .bottom
case .bottom:
return .bottomTrailing
case .bottomTrailing:
return .trailing
case .trailing:
return .topTrailing
case .topTrailing:
return .top
default:
print("Unknown point")
return .top
}
}
}
Result:
Note: To get an even smoother animation, maybe check out rotationEffect
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.