Проблема с анимацией animatableData в SwiftUI - PullRequest
3 голосов
/ 29 марта 2020

SwiftUI не только дает нам автоматическую c анимацию ... он позволяет нам контролировать процесс анимации, используя свойство animatableData. Так круто!

Только я не могу заставить его работать. Следующий код отображает циферблат на экране (цифры 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))
                }
            }
        }
    }
}

Ответы [ 2 ]

2 голосов
/ 10 апреля 2020

Здесь возможен подход. Протестировано с 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))
                }
            }
        }
    }
}

Необязательно: также я бы порекомендовал вам округлить значения точек для лучшей целостности, однако это не так уж важно.

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))
    }
}
0 голосов
/ 29 марта 2020

проблема в злой математике ... вы вычисляете конечные положения. Apple просто добавляет шаги из одной позиции в другую (в виде линии), так что это то, что вы видите. Если вы переключаетесь с 0 на 1, это «выглядит» как круговое движение, но оно также является линейным;) решение будет заключаться в том, чтобы вручную вычислить позиции x, y по кругу в зависимости от значений часового смещения

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...