swift - 如何在执行新动画时保持初始动画运行?
问题描述
我很难弄清楚这个动画的事情。问题是, .onAppear 摇晃动画(应该永远循环)在视图被拖动后立即停止并冻结(它有另一个动画,以便它平滑地移动到拖动位置)。
有没有办法让 onAppear 动画独立于被拖动的视图运行?需要注意的重要一点是,我确实需要依赖于数组的位置(因此拖动手势直接写入数据),并且我根本不需要将摆动(大小动画)绑定到数组。
动画在拖动时冻结的插图(不受欢迎 - 想要在被拖动期间和之后转圈以仍然摆动)
请看代码:
var body: some View {
Circle()
// .resizable()
.frame(width:size.width, height: size.height) //self.size is a state var
.foregroundColor(color)
.position(pos) //pos is a normal var bound to an array row
.gesture(DragGesture()
.onChanged { gesture in
withAnimation(.default) {
ballStorage.balls[numberInArray].position = gesture.location
}
}
.onEnded { gesture in
ballStorage.checkOverlaps(for: numberInArray)
}
) .onAppear {
withAnimation(Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)) {
size = CGSize(width: size.width+20, height: size.height+20)
}
}
}
}
解决方案
您需要用自己的动画将圆圈分成自己的视图,然后内部动画将独立于外部动画。
这是关于以某种方式复制的代码的解决方案演示。使用 Xcode 12.1 / iOS 14.1 准备。
struct Ball: Identifiable, Hashable {
let id = UUID()
var position = CGPoint.zero
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
struct BallView: View {
let ball: Ball
var color = Color.blue
@State private var size = CGSize(width: 40, height: 40)
var body: some View {
Circle()
.frame(width:size.width, height: size.height) //self.size is a state var
.animation(Animation.easeInOut(duration: 1).repeatForever(autoreverses: true), value: size)
.foregroundColor(color)
.onAppear {
size = CGSize(width: size.width+20, height: size.height+20)
}
}
}
struct ContentView: View {
@State private var balls = [Ball(position: CGPoint(x: 100, y: 100)), Ball(position: CGPoint(x: 100, y: 200))]
@State private var off = CGSize.zero
@State private var selected = -1
var body: some View {
ZStack {
ForEach (Array(balls.enumerated()), id: \.1) { i, ball in
BallView(ball: ball)
.offset(x: i == selected ? off.width : 0, y: i == selected ? off.height : 0)
.position(ball.position)
.gesture(DragGesture()
.onChanged { gesture in
self.selected = i
withAnimation(.default) {
self.off = gesture.translation
}
}
.onEnded { gesture in
let pt = balls[i].position
self.balls[i].position = CGPoint(x: pt.x + gesture.translation.width, y: pt.y + gesture.translation.height)
self.off = .zero
self.selected = -1
// ballStorage.checkOverlaps(for: numberInArray)
}
)
}
}
}
}
推荐阅读
- c# - 如何使用 TryFindParent
- python - 如何在分组的 Python 数据框中获取值
- mongodb - mongodb中如何查询子对象中的数组元素是否大于0并删除
- pug - Alpine.js 和 Spruce 中的变量插值
- regex - 正则表达式匹配javascript中的电子邮件ID?
- git - 如何修复 git 错误:找不到存储库
- sql - 用于更新所有以数字开头的列值的 SQL 脚本,并且 - 在 Postgresql 中为空白
- asp.net-mvc - MVC 应用程序有两个 cookie
- css - 在移动版 Chrome 上呈现的 CSS 链接/按钮白色像素线
- c++ - 访问着色器中的索引缓冲区 (Directx 11)