swift - 如何在 CGAffineTransform 上为 SwiftUI 中的旋转角度添加动画?
问题描述
我需要使用rotationAngle 为CGAffineTransform 设置动画,但我不知道是否可行,因为CGAffineTransform 不符合Animatable。Maby 带有“withAnimation”,但我不明白如何使用它。我知道我可以使用rotationEffect,但出于某些原因,我必须使用CGAffineTransform。
我的代码:
import SwiftUI
import CoreLocation
struct Arrow: View {
var locationManager = CLLocationManager()
@ObservedObject var location: LocationManager = LocationManager()
private var animationArrow: Animation {
Animation
.easeInOut(duration: 0.2)
}
var body: some View {
VStack {
Image("arrow")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300, height: 300)
.transformEffect(
CGAffineTransform(translationX: -150, y: -150)
.concatenating(CGAffineTransform(rotationAngle: CGFloat(-location.heading.degreesToRadians)))
.concatenating(CGAffineTransform(translationX: 150, y: 150))
)
.animation(animationArrow)
Text(String(location.heading.degreesToRadians))
.font(.system(size: 20))
.fontWeight(.light)
.padding(.top, 15)
Text(String(location.coordinates[0]))
.font(.system(size: 20))
.fontWeight(.light)
.padding(.top, 15)
Text(String(location.coordinates[1]))
.font(.system(size: 20))
.fontWeight(.light)
.padding(.top, 15)
}
}
}
解决方案
如果你不能使用任何现有的动画效果,你需要教 SwiftUI 如何动画你的变换矩阵。您可以使用 GeometryEffect 来做到这一点。它是一个同时符合 Animatable 和 ViewModifier 的协议。
如果您想全面了解 GeometryEffect 的工作原理,请查看我的帖子:https ://swiftui-lab.com/swiftui-animations-part2/
这是一个工作示例:
struct ContentView: View {
@State private var animate = false
var body: some View {
Rectangle()
.frame(width: 50, height: 50)
.modifier(MyEffect(angle: animate ? .pi * 2 : 0))
.onTapGesture {
withAnimation(.easeInOut(duration: 2.0)) {
self.animate.toggle()
}
}
}
}
struct MyEffect: GeometryEffect {
var angle: CGFloat
var animatableData: CGFloat {
get { angle }
set { angle = newValue }
}
func effectValue(size: CGSize) -> ProjectionTransform {
return ProjectionTransform(CGAffineTransform(rotationAngle: angle))
}
}
响应您的评论,您可以将 withAnimation 与任何变量一起使用,而不仅仅是布尔值。如果变量最终影响可动画参数,它将动画。这是一个例子:
struct ContentView: View {
@State private var angle: CGFloat = 0
var body: some View {
VStack {
Rectangle()
.frame(width: 50, height: 50)
.modifier(MyEffect(angle: angle))
Button("Go to 0") {
withAnimation(.easeInOut(duration: 2.0)) {
self.angle = 0
}
}
Button("Go to 360") {
withAnimation(.easeInOut(duration: 2.0)) {
self.angle = .pi * 2
}
}
}
}
}
推荐阅读
- react-native - 已解决如何通过导航在 React Native 中设置全屏背景图像
- ethereum - 从 bigNumber 中提取纯整数
- python - Prefix_to_Postfix:乘法没有出现在正确的位置
- python - 如何让我的机器人等待响应?
- nuxt.js - Nuxt + GraphQL (Apollo) 上传文件
- angular - 输入'无效| 可观察的
' 不可分配给类型 'ObservableInput '。类型 'void' 不可分配给类型 'ObservableInput ' - flutter - 断言失败::_network_image_io 'url'!= null:不正确
- javascript - Ajax Get后的JQuery条件格式td
- javascript - MUI:一个组件正在改变 Select 的不受控值状态以被控制
- android-studio - 运行“应用程序”时如何自动打开运行选项卡?