SwiftUI动画—只需5个步骤即可构建加载微调器
自SwiftUI出现以来,编写UI代码的方式就已经改变了,它为我们发展创造力提供了很多功能,这些功能之一与动画状态转换有关。
本文会指引你构建自定义加载微调器,下图就是基于此设计的:
此外,你可以在我的项目存储库中找到所有操作细节:
让我们开始吧!
1.创建
针对此动画,我们将使用 Circle
结构。如你所见,此次进行的小改动将帮助我们获得所需的微调框外观。
struct Spinner: View {
var body: some View {
ZStack {
SpinnerCircle()
}.frame(width: 200, height: 200)
}
}
struct SpinnerCircle: View {
var body: some View {
Circle()
.stroke(style: StrokeStyle(lineWidth: 20, lineCap: .round))
}
}
- 创建一个名为
Spinner
的新SwiftUI文件。 - 再创建一个名为
SpinnerCircle
的视图,其中包含一个Circle
。 - 使用
stroke(style:)
修改器获得微调器外观。 - 最后,在主视图中,构建一个200像素的
SpinnerCircle
框架。
当前预览
2.修剪
要包含的下一个修饰符是 trim(from:to:)
,这样我们就可以利用提供的参数来绘制部分形状。具体工作方式如下:
考虑到这一点,我们在 SpinnerCircle
视图中做了一些更改:
struct SpinnerCircle: View {
var start: CGFloat
var end: CGFloat
var body: some View {
Circle()
.trim(from: start, to: end)
.stroke(style: StrokeStyle(lineWidth: 20, lineCap: .round))
}
}
3.旋转
最后,我们将包含另一个修饰符。 rotationEffect()
可以使我们的视图旋转到特定的角度。
拥有半个修剪圆( .trim(from:0.0 to: 0.5)
),并且 rotationEffect(d)
中的 d
是先前定义的一个变量,然后旋转修饰符将导致:
要做的更改:
struct SpinnerCircle: View {
var start: CGFloat
var end: CGFloat
var rotation: Angle
var color: Color
var body: some View {
Circle()
.trim(from: start, to: end)
.stroke(style: StrokeStyle(lineWidth: 20, lineCap: .round))
.fill(color)
.rotationEffect(rotation)
}
}
我们完成了!并且已经准备好进行动画处理。还要注意的是,我们包括了 fill
修饰符和 color
属性。
在这一点上, Spinner
整体视图是不完整的,不用担心,这一问题在下一部分会得到解决。
4.对其进行动画处理
回到主视图,我们要定义一些常量,例如微调器旋转的持续时间以及将微调器置于初始位置的度数:
struct Spinner: View {
let rotationTime: Double = 0.75
let fullRotation: Angle = .degrees(360)
static let initialDegree: Angle = .degrees(270)
var body: some View { ... }
}
动画将基于已更改的 SpinnerCircle
修剪和旋转属性,因此包含带有 State
的以下变量:
@State var spinnerStart: CGFloat = 0.0
@State var spinnerEndS1: CGFloat = 0.03
@State var rotationDegreeS1 = initialDegree
最后,主体中包含 SpinnerCircle
视图、一些动画方法和一个 .onAppear()
块:
var body: some View {
ZStack {
// S1
SpinnerCircle(start: spinnerStart, end: spinnerEndS1, rotation: rotationDegreeS1, color: darkBlue)
}.frame(width: 200, height: 200)
.onAppear() {
Timer.scheduledTimer(withTimeInterval: animationTime, repeats: true) { (mainTimer) in
self.animateSpinner()
}
}
}
// MARK: Animation methods
func animateSpinner(with timeInterval: Double, completion: @escaping (() -> Void)) {
Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { _ in
withAnimation(Animation.easeInOut(duration: rotationTime)) {
completion()
}
}
}
func animateSpinner() {
}
- 动画方法将在特定时间间隔内更新微调器的圆圈属性,从而创建单独的动画。
- 一旦视图出现,微调框将使用
Timer
不断进行动画处理。 animationTime
代表动画的总时间。它是动画方法中定义所有时间间隔的总和。- 将其定义为
let animationTime: Double = 1.9
。
我们准备好了,那就开始制作动画吧!
在 animateSpinner()
方法中,包括在 rotationTime
期间填充 Circle
形状所需的代码,具体如下:
animateSpinner(with:rotationTime){self.spinnerEndS1 = 1.0}
当前预览
在下面的旋转中( rotationTime x 2 ),我们将返回到初始形状:
animateSpinner(with:(rotationTime * 2)){
self.spinnerEndS1 = 0.03
}
当前预览
最后的一个技巧。我们将在上一个动画之前进行一个完整的旋转(360°)。这样,我们就可以实现所需的动画了:
animateSpinner(with:(rotationTime * 2)
-0.025 ){ self.rotationDegreeS1 + = fullRotation
}
当前预览
- 通过测试得到
0.025
。我们尝试几个值,直到找到一个合适的值为我们提供一个流畅的动画。
5.完成
其余练习只是对先前步骤的重复。如果要检查我们正使用的设计,你会注意到其余部分也都是 Circle
。
因此,如果我们在主视图中添加此颜色和一些颜色详细信息,则它看起来就像:
ZStack {
darkGray
.edgesIgnoringSafeArea(.all)
ZStack {
// S3
SpinnerCircle(start: spinnerStart, end: spinnerEndS2S3, rotation: rotationDegreeS3, color: darkViolet)
// S2
SpinnerCircle(start: spinnerStart, end: spinnerEndS2S3, rotation: rotationDegreeS2, color: darkPink)
// S1
SpinnerCircle(start: spinnerStart, end: spinnerEndS1, rotation: rotationDegreeS1, color: darkBlue)
}.frame(width: 200, height: 200)
}
spinnerEndS2S3
的初始化方式与spinnerEndS1
相同。rotationDegreeS2
和rotationDegreeS3
与rotationDegreeS1
相同。- 使用的颜色是自定义的颜色,可以检查存储库或使用你自己的颜色。
另一方面, animateSpinner()
将包含所需动画:
func animateSpinner() {
animateSpinner(with: rotationTime) { self.spinnerEndS1 = 1.0 }
animateSpinner(with: (rotationTime * 2) - 0.025) {
self.rotationDegreeS1 += fullRotation
self.spinnerEndS2S3 = 0.8
}
animateSpinner(with: (rotationTime * 2)) {
self.spinnerEndS1 = 0.03
self.spinnerEndS2S3 = 0.03
}
animateSpinner(with: (rotationTime * 2) + 0.0525) { self.rotationDegreeS2 += fullRotation }
animateSpinner(with: (rotationTime * 2) + 0.225) { self.rotationDegreeS3 += fullRotation }
}
这样,就大功告成了:
当前预览
如果你对SwiftUI动画感兴趣并希望看到更多内容,可以着手于该项目或在Instagram上关注我:
转自:https://www.agora.io/cn/community/blog/121-category/21094