在WatchOS上的SwiftUI中,如何动画矩形(或与此相关的任何视图)的宽度,以使其开始于某个值并在指定的时间动画为另一个值?
具体来说,我想给“矩形”设置动画以指示到下一整分钟或一分钟后接下来的30秒的剩余时间。
我所看到的所有示例都是基于Timer.scheduledTimer
以较高的速度触发并设置@State
变量,但是我的理解是,尤其是在WatchOS上,应避免这种情况。有更好的方法吗?
这是我拥有的基于计时器/状态的代码,但我觉得应该有一种更有效的方法:
import SwiftUI
func percentage() -> CGFloat {
1 - CGFloat(fmod(Date().timeIntervalSince1970, 30) / 30)
}
struct ContentView: View {
@State var ratio: CGFloat = percentage()
let timer = Timer.publish(every: 1 / 60, on:.main, in:.common).autoconnect()
var body: some View {
GeometryReader { geometry in
ZStack {
Rectangle()
.foregroundColor(Color.gray)
.frame(width:geometry.size.width, height:5)
HStack {
Rectangle()
.foregroundColor(Color.red)
.frame(width:geometry.size.width * self.ratio, height:5)
Spacer()
}
}
}.onReceive(self.timer) { _ in
self.ratio = percentage()
}
}
}
答案 0 :(得分:1)
我认为使用动画的“更有效的方式”:
struct AnimationRectangle: View {
struct AnimationRectangle: View {
@State private var percentage: CGFloat = 0.0
// count, how much time left to nearest 30 seconds
@State private var animationDuration = 30 - Double(fmod(Date().timeIntervalSince1970, 30))
private var repeatedAnimationFor30Seconds: Animation {
return Animation.easeInOut(duration: 30)
.repeatForever(autoreverses: false)
}
var body: some View {
VStack {
// just showing duration of current animation
Text("\(self.animationDuration)")
ZStack {
Rectangle()
.foregroundColor(.gray)
GeometryReader { geometry in
HStack {
Rectangle()
.foregroundColor(.green)
.frame(width: geometry.size.width * self.percentage)
Spacer()
}
}
}
.frame(height: 5)
.onAppear() {
// first animation without repeating
withAnimation(Animation.easeInOut(duration: self.animationDuration)) {
self.percentage = 1.0
}
// other repeated animations
DispatchQueue.main.asyncAfter(deadline: .now() + self.animationDuration) {
self.percentage = 0.0
self.animationDuration = 30.0
withAnimation(self.repeatedAnimationFor30Seconds) {
self.percentage = 1.0
}
}
}
}
}
}
struct AnimationRectangle_Previews: PreviewProvider {
static var previews: some View {
AnimationRectangle()
}
}