如何以 0 到 1 的比例对圆形图像进行动画处理,同时沿圆的圆周以 7 点钟的起始位置和 11 点钟的缩放结束位置进行动画处理,然后在 11 时以从 1 到 0 的不透明度进行动画处理点到三点。然后将图像重新定位回 7 点钟位置并循环播放动画。使用以下代码,我可以同时缩放和旋转,但它不会沿着圆周移动。我不知道如何在缩放和旋转过程中偏移动画,使其保持沿着圆圈。
struct ContentView: View {
@State private var startAngle: Double = -45
@State private var endAngle: Double = 120
@State private var animationValue: Double = 0.0
var body: some View {
ZStack {
let width: CGFloat = 60
Circle()
.stroke(.black, lineWidth: 1.0)
.frame(width: width)
.overlay {
Image(systemName: "circle.fill")
.offset(x: -width/2)
.modifier(ScaleAndRotateModifier(value: animationValue,
startAngle: startAngle,
endAngle: endAngle))
.onAppear {
withAnimation(.easeInOut(duration: 1.0).repeatForever(autoreverses: true)) {
animationValue = 1.0
}
}
}
}
.foregroundStyle(.black)
.padding()
}
}
struct ScaleAndRotateModifier: AnimatableModifier {
var value: Double
var startAngle: Double
var endAngle: Double
var animatableData: Double {
get { value }
set { value = newValue }
}
func body(content: Content) -> some View {
content
.rotationEffect(Angle(degrees: startAngle + value * endAngle), anchor: .center)
.scaleEffect(value * 0.5)
}
}
由于这个动画涉及多个阶段,所以这里使用
keyframeAnimator
会很方便。
编写一个包含您想要设置动画的所有属性的结构:
struct AnimatedProperties {
var angle: Angle = .degrees(120)
var scale: CGFloat = 0
var opacity: CGFloat = 1
}
那么你可以做
let width: CGFloat = 60
Circle()
.stroke(.black, lineWidth: 1.0)
.frame(width: width)
.overlay {
Image(systemName: "circle.fill")
.keyframeAnimator(initialValue: AnimatedProperties()) { content, properties in
content
.scaleEffect(properties.scale)
.opacity(properties.opacity)
.offset(x: width / 2 * cos(properties.angle.radians), y: width / 2 * sin(properties.angle.radians))
} keyframes: { properties in
KeyframeTrack(\.angle) {
LinearKeyframe(.degrees(360), duration: 2)
}
KeyframeTrack(\.scale) {
LinearKeyframe(1, duration: 1)
}
KeyframeTrack(\.opacity) {
LinearKeyframe(1, duration: 1)
LinearKeyframe(0, duration: 1)
}
}
}
注意这一行:
.offset(x: width / 2 * cos(properties.angle.radians), y: width / 2 * sin(properties.angle.radians))
这就是计算给定角度所需偏移的方法。
这里我假设您希望圆圈立即跳回其起始位置。如果您也想将这部分动画设置为持续 1 秒,请将
\.angle
轨道更改为一直到 480 度,并持续 3 秒。
KeyframeTrack(\.angle) {
LinearKeyframe(.degrees(480), duration: 3)
}