使渐变视图动画颜色在 SwiftUI 中沿一个方向旋转
Make gradient view animation colors swirl in one direction in SwiftUI
所以我有一个线性渐变视图,并且我有使用 .animation()
修饰符设置动画的颜色。现在,当我调整渐变的 start
和 end
点并使用 .easeInAndOut()
修改器设置动画时,颜色会来回旋转。我希望颜色沿一个方向顺时针反复旋转,但它却来回旋转。
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)
}
}
渐变颜色来回旋转。我希望颜色顺时针方向 旋转,平滑且重复。
开始调试吧!首先,在大量 self.start = ...
序列之前和之后,尝试添加 print
语句。
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)")
您会注意到这两个 print
几乎同时发生。
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)
这是因为 Swift 代码在极短的时间内一行一行地立即执行。结果,start
总是变成 (x: 0.0, y: 0.5)
(.leading
),而 end
总是变成 (x: 1.0, y: 0.5)
(.trailing
)。您的渐变可能根本就没有动画!
要修复,您应该简单地获取 start
和 end
的当前值,然后手动计算下一个值。
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
}
}
}
结果:
注意:要获得更流畅的动画,请查看 rotationEffect
。
所以我有一个线性渐变视图,并且我有使用 .animation()
修饰符设置动画的颜色。现在,当我调整渐变的 start
和 end
点并使用 .easeInAndOut()
修改器设置动画时,颜色会来回旋转。我希望颜色沿一个方向顺时针反复旋转,但它却来回旋转。
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)
}
}
渐变颜色来回旋转。我希望颜色顺时针方向 旋转,平滑且重复。
开始调试吧!首先,在大量 self.start = ...
序列之前和之后,尝试添加 print
语句。
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)")
您会注意到这两个 print
几乎同时发生。
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)
这是因为 Swift 代码在极短的时间内一行一行地立即执行。结果,start
总是变成 (x: 0.0, y: 0.5)
(.leading
),而 end
总是变成 (x: 1.0, y: 0.5)
(.trailing
)。您的渐变可能根本就没有动画!
要修复,您应该简单地获取 start
和 end
的当前值,然后手动计算下一个值。
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
}
}
}
结果:
注意:要获得更流畅的动画,请查看 rotationEffect
。