ios - 在 SwiftUI 中使用 animatableData 进行动画处理时出现问题

标签 ios animation rotation swiftui

SwiftUI 不仅为我们提供了自动动画……它还让我们可以使用 animatableData 控制动画的发生方式。属性(property)。非常酷!

只有我无法让它工作。以下代码在屏幕上显示一个钟面(数字 0…11 🙂)并显示一个切换开关。切换开关会将数字旋转 180 度,并进行动画处理。或者这就是我的意图。但不是每个数字围绕数字圈走一条动画路径,而是每个数字沿着一条直线移动到它的新位置……这样数字圈就会折叠到圆的中心点,然后重新爆炸成它的新配置:

enter image description here
animatableData属性未被 SwiftUI 引用。知道为什么吗?

(请注意,使用标准旋转动画是行不通的,因为这会使所有数字颠倒。)

import SwiftUI

struct ContentView: View {
    @State var state: Bool = false

    var body: some View {
        VStack {
            CircleView(hoursOffset: CGFloat(state ? 6 : 0 ))
                .aspectRatio(contentMode: .fit)
            Toggle(isOn: $state, label: { Text("Rotate 180°?") })
                .frame(maxWidth: 200).padding()
        }
    }
}

extension CGPoint {
    static func onCircle(hours: CGFloat, size: CGFloat) -> CGPoint {
        let radians = (3 - hours) * CGFloat.pi / CGFloat (6)
        let hypotenuse = size / 2
        return CGPoint(x: size / 2 + 0.8 * hypotenuse * cos(radians),
                       y: size / 2 - 0.8 * hypotenuse * sin(radians))
    }
}

struct CircleView: View {

    var hoursOffset: CGFloat

    public var animatableData: CGFloat {
        get { hoursOffset }
        set { self.hoursOffset = newValue }
    }

    var body: some View {
        GeometryReader() { geo in
            ForEach(0..<12) { hour in
                ZStack {
                    Text("\(hour)")
                        .position(CGPoint.onCircle(hours: CGFloat(hour) + self.hoursOffset, size: geo.size.width))
                        .animation(Animation.easeInOut(duration: 2.0))
                }
            }
        }
    }
}

最佳答案

这是可能的方法。使用 Xcode 11.4/iOS 13.4 测试。刚刚animatableData在 View 中不起作用 - 您必须将其放入 AnimatableModifier .
demo

struct CircleMoving: AnimatableModifier {
    var hoursOffset: CGFloat
    var hour: CGFloat
    var size: CGFloat

    public var animatableData: CGFloat {
        get { hoursOffset }
        set { self.hoursOffset = newValue }
    }

    func body(content: Content) -> some View {
        content
            .position(CGPoint.onCircle(hours: hour + hoursOffset, size: size))
    }
}


struct CircleView: View {

    var hoursOffset: CGFloat

    var body: some View {
        GeometryReader() { geo in
            ForEach(0..<12) { hour in
                ZStack {
                    Text("\(hour)")
                        .modifier(CircleMoving(hoursOffset: self.hoursOffset, hour: CGFloat(hour), size: geo.size.width))
                }
            }
        }
        .animation(.easeInOut(duration: 3.0), value: hoursOffset) // !!!
    }
}
可选:我还建议您舍入点值以获得更好的完整性,但这并不重要。
extension CGPoint {
    static func onCircle(hours: CGFloat, size: CGFloat) -> CGPoint {
        let radians = (3 - hours) * CGFloat.pi / CGFloat (6)
        let hypotenuse = size / 2
        return CGPoint(x: (size / 2 + 0.8 * hypotenuse * cos(radians)).rounded(.up),
                       y: (size / 2 - 0.8 * hypotenuse * sin(radians)).rounded(.up))
    }
}

关于ios - 在 SwiftUI 中使用 animatableData 进行动画处理时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60909355/

相关文章:

ios - 滑动带有动画的 UIView

ios - 发电机 ios

ios - Sierra : Keychain ignores access control settings and UI-prompts for permission 中的安全/代码设计

c# - WPF 中的图标混合动画

c++ - UE4 - 使用 CameraComponent 时观众不旋转(俯仰)

iphone - 如何在 Interface Builder 中旋转 UIImageView?

iphone - 将参数传递给选择器

java - 如何使用 JFrame、JLabel、使用 setForeground 创建颜色模拟?

javascript - Angular ng-show ng-hide 动画

javascript - 如何旋转这个形状?