注册

SwiftUI动画—只需5个步骤即可构建加载微调器

3ff9efac046a76dd091886e178b2a6ad.png

自SwiftUI出现以来,编写UI代码的方式就已经改变了,它为我们发展创造力提供了很多功能,这些功能之一与动画状态转换有关。

本文会指引你构建自定义加载微调器,下图就是基于此设计

6b2396bf27d5d923d4a167eb51d87616.gif

此外,你可以在我的项目存储库中找到所有操作细节:

让我们开始吧!

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 框架。

11fc08c804c46abb33abddb0730bb9a9.png
当前预览

2.修剪

要包含的下一个修饰符是 trim(from:to:) ,这样我们就可以利用提供的参数来绘制部分形状。具体工作方式如下:

24f247c5b3656acac6f09b84c8f105cf.png

考虑到这一点,我们在 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 是先前定义的一个变量,然后旋转修饰符将导致:

ad77a3bb421ccef65d369819813d4dac.png

要做的更改:

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}

94ae03d7528616bafc3918a5594de3d7.gif
当前预览

在下面的旋转中( rotationTime x 2 ),我们将返回到初始形状:

animateSpinner(with:(rotationTime * 2)){     
self.spinnerEndS1 = 0.03
}

bdbd512675221f3fbf5e84ce5fe2f10a.gif
当前预览

最后的一个技巧。我们将在上一个动画之前进行一个完整的旋转(360°)。这样,我们就可以实现所需的动画了:

animateSpinner(with:(rotationTime * 2
-0.025 ){ self.rotationDegreeS1 + = fullRotation
}

81a7d736375a69423f36573da505582f.gif
当前预览

  • 通过测试得到 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 }
}

这样,就大功告成了:

3abd0dc8fe12fbf22be66f21d57b5866.gif
当前预览

如果你对SwiftUI动画感兴趣并希望看到更多内容,可以着手于该项目或在Instagram上关注我:

转自:https://www.agora.io/cn/community/blog/121-category/21094

0 个评论

要回复文章请先登录注册