Problem animating with animatableData in SwiftUI

丶灬走出姿态 提交于 2020-07-21 03:44:56

问题


SwiftUI not only gives us get automatic animation… it lets us control how the animation occurs, using the animatableData property. So cool!

Only I can't get it to work. The following code displays a clock face on the screen (numbers 0…11 🙂) and shows a toggle switch. Switching the toggle rotates the numbers by 180 degrees, animated. Or that is my intent. But instead of each number taking an animated path around the circle of numbers, each number moves along a straight line to its new position… so that the circle of numbers collapses to the circle's center point and then re-explodes into its new configuration:

The animatableData property is not being referenced by SwiftUI. Any idea why?

(Note that it wouldn't work to use a standard rotation animation, because that would turn all the numbers upside down.)

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))
                }
            }
        }
    }
}

回答1:


Here is possible approach. Tested with Xcode 11.4 / iOS 13.4. Just animatableData in View does not work - you have to put it in AnimatableModifier.

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))
                }
            }
        }
    }
}

Optional: also I would recommend you round point values for better integrity, however it is not much important.

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))
    }
}



回答2:


the problem is the evil mathematics...you are calculating the endpositions. Apple does just adding steps from one position to another (as a line) so this is what you see. If you toggle from 0 to 1 it "looks" like a circular move, but it is also linear ;) the solution would be, to calculate the x,y positions manually ON the circle depending on your hours offset values



来源:https://stackoverflow.com/questions/60909355/problem-animating-with-animatabledata-in-swiftui

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!