Как оживить путь в SwiftUI
Будучи незнакомым со SwiftUI и тем фактом, что пока еще не так много документации по этой новой среде. Мне было интересно, если кто-нибудь был знаком с тем, как можно было бы оживить Path
в SwiftUI.
Например, учитывая вид, скажем так RingView
:
struct RingView : View {
var body: some View {
GeometryReader { geometry in
Group {
// create outer ring path
Path { path in
path.addArc(center: center,
radius: outerRadius,
startAngle: Angle(degrees: 0),
endAngle: Angle(degrees: 360),
clockwise: true)
}
.stroke(Color.blue)
// create inner ring
Path { path in
path.addArc(center: center,
radius: outerRadius,
startAngle: Angle(degrees: 0),
endAngle: Angle(degrees: 180),
clockwise: true)
}
.stroke(Color.red)
.animation(.basic(duration: 2, curve: .linear))
}
}
.aspectRatio(1, contentMode: .fit)
}
}
Что отображается:
Теперь мне было интересно, как мы можем анимировать внутреннее кольцо, то есть красную линию внутри синей линии. Анимация, которую я ищу, была бы простой анимацией, где путь появляется от начала и проходит до конца.
Это довольно просто, используя CoreGraphics и старый фреймворк UIKit, но это не похоже на добавление простого .animation(.basic(duration: 2, curve: .linear))
на внутренний путь и отображение вида с withAnimation
Блок делает что угодно.
Я просмотрел предоставленные Apple руководства по SwiftUI, но они действительно охватывают анимацию перемещения / масштабирования только в более подробных представлениях, таких как Image
,
Любое руководство о том, как оживить Path
или же Shape
в SwiftUI?
1 ответ
Анимация путей демонстрируется в сеансе WWDC 237 ( Создание пользовательских видов с помощью SwiftUI). Ключ использует AnimatableData. Вы можете подскочить до 31:23, но я рекомендую начать хотя бы с минуты 27:47.
Вам также нужно будет загрузить пример кода, потому что удобно, интересные фрагменты не показаны (и не объяснены) в презентации: https://developer.apple.com/documentation/swiftui/drawing_and_animation/building_custom_views_in_swiftui
Дополнительная документация: Поскольку я первоначально опубликовал ответ, я продолжил исследовать, как анимировать Path, и опубликовал статью с подробным объяснением протокола Animatable и его использования с Paths: https://swiftui-lab.com/swiftui-animations-part1/
Обновить:
Я работал с анимацией пути формы. Вот ГИФ.
И вот код:
ВАЖНО: код не анимируется в предварительных просмотрах Xcode Live. Он должен работать на симуляторе или на реальном устройстве.
import SwiftUI
struct ContentView : View {
var body: some View {
RingSpinner().padding(20)
}
}
struct RingSpinner : View {
@State var pct: Double = 0.0
var animation: Animation {
Animation.basic(duration: 1.5).repeatForever(autoreverses: false)
}
var body: some View {
GeometryReader { geometry in
ZStack {
Path { path in
path.addArc(center: CGPoint(x: geometry.size.width/2, y: geometry.size.width/2),
radius: geometry.size.width/2,
startAngle: Angle(degrees: 0),
endAngle: Angle(degrees: 360),
clockwise: true)
}
.stroke(Color.green, lineWidth: 40)
InnerRing(pct: self.pct).stroke(Color.yellow, lineWidth: 20)
}
}
.aspectRatio(1, contentMode: .fit)
.padding(20)
.onAppear() {
withAnimation(self.animation) {
self.pct = 1.0
}
}
}
}
struct InnerRing : Shape {
var lagAmmount = 0.35
var pct: Double
func path(in rect: CGRect) -> Path {
let end = pct * 360
var start: Double
if pct > (1 - lagAmmount) {
start = 360 * (2 * pct - 1.0)
} else if pct > lagAmmount {
start = 360 * (pct - lagAmmount)
} else {
start = 0
}
var p = Path()
p.addArc(center: CGPoint(x: rect.size.width/2, y: rect.size.width/2),
radius: rect.size.width/2,
startAngle: Angle(degrees: start),
endAngle: Angle(degrees: end),
clockwise: false)
return p
}
var animatableData: Double {
get { return pct }
set { pct = newValue }
}
}