边学习边学习! Swift UI动画指标版


介绍

边制作边学习!动画指示符版本。

完成后,动画将如下所示。
ylcjk-49v22.gif

让我们做

圈一个

首先,制作一个基圆。

1
2
3
4
5
6
7
import SwiftUI

struct ContentView: View {
    var body: some View {
        Circle()
    }
}

スクリーンショット 2020-02-04 13.28.00.png

挖出一个圆圈以制成戒指

使用stroke方法循环

圆。

1
2
3
4
func stroke(S, lineWidth: CGFloat) -> View
func stroke(S, style: StrokeStyle) -> View
func stroke(lineWidth: CGFloat) -> Shape
func stroke(style: StrokeStyle) -> Shape

https://developer.apple.com/documentation/swiftui/shape

<S>在这里可以是符合ShapeStyle的类型。

您可以指定颜色,例如"颜色"和"渐变"以及颜色渐变。
https://developer.apple.com/documentation/swiftui/shapestyle

首先,将颜色设为绿色以便于理解。

1
2
3
4
5
6
struct ContentView: View {
    var body: some View {
            Circle()
                .stroke(Color.green)
    }
}

スクリーンショット 2020-02-09 23.52.34.png

这会使线变细且难以看清,因此加宽线使其更容易看清。
为此,我们将应用StrokeStyle

描边样式

一个对象,用于定义边框或分隔线的颜色,宽度和样式。
https://developer.apple.com/documentation/apple_news/strokestyle

1
2
3
4
5
6
        StrokeStyle(lineWidth: CGFloat,
                    lineCap: CGLineCap,
                    lineJoin: CGLineJoin,
                    miterLimit: CGFloat,
                    dash: [CGFloat],
                    dashPhase: CGFloat)

lineWidth

线宽默认为1

由于它是

,因此将lineWidth设置为8以增加线宽。

1
2
3
4
5
6
struct ContentView: View {
    var body: some View {
            Circle()
                .stroke(Color.green, style: StrokeStyle(lineWidth: 8))
    }
}

スクリーンショット 2020-02-10 0.24.06.png

如果它仍然是

圆,则即使旋转它也不知道,因此请使用trim方法对其进行修整。

trim(from:to:)

1
func trim(from startFraction: CGFloat = 0, to endFraction: CGFloat = 1) -> some Shape

https://developer.apple.com/documentation/swiftui/shape/3365372-trim

1
2
3
4
5
6
7
struct ContentView: View {
    var body: some View {
        Circle()
            .trim(from: 0, to: 0.4)
            .stroke(Color.green, style: StrokeStyle(lineWidth: 8))
    }
}

スクリーンショット 2020-02-11 15.47.29.png

如果原样保留圆,则圆会很大,因此请使用frame方法进行调整。

1
2
3
4
5
6
7
8
9
10
import SwiftUI

struct ContentView: View {
    var body: some View {
        Circle()
            .trim(from: 0, to: 0.6)
            .stroke(Color.green, style: StrokeStyle(lineWidth: 8))
            .frame(width: 48, height: 48)
    }
}

スクリーンショット 2020-02-11 15.54.22.png

它变成了指示器大小!

スクリーンショット 2020-02-10 0.59.15.png

尖角将变为圆形。
为此,请使用StrokeStyle中的lineCap

CGLineCap(iOS 2.0)

<表格>

CGLineCap

行尾

结束

图片


<身体>

.butt

正方形

到指定路径的端点

スクリーンショット 2020-02-08 22.37.32.png

.round

超出指定路径的端点

スクリーンショット 2020-02-08 22.37.42.png

.square

正方形

从指定路径的端点开始超过行宽的一半

スクリーンショット 2020-02-08 22.37.52.png


https://developer.apple.com/documentation/coregraphics/cglinecap

1
2
3
4
5
6
7
8
9
struct ContentView: View {
    var body: some View {
        Circle()
            .trim(from: 0, to: 0.6)
            .stroke(Color.green,
                    style: StrokeStyle(lineWidth: 8, lineCap: .round))
            .frame(width: 48, height: 48)
    }
}

スクリーンショット 2020-02-10 1.29.45.png

CGLineJoin(iOS 2.0)

如果图形有角,则可以看到更改,如下所示。
但是,由于这次创建的指示器是弧形的,因此请使其顺畅流动。

<表格>

.miter

.round

.bevel


<身体>

lineJoin

スクリーンショット 2020-02-09 0.25.20.png

スクリーンショット 2020-02-09 0.25.27.png

スクリーンショット 2020-02-09 0.29.17.png


miterLimit

.miter应用于笔尖形状的阈值(默认10)

dash

将虚线的形状指定为数组。

1
[線の長さ, 空白の長さ, 2番目の線の長さ, 2番目の空白の長さ, ...]
1
2
3
4
5
6
7
8
9
10
11
12
struct ContentView: View {
    var body: some View {
        Circle()
            .trim(from: 0, to: 0.4)
            .stroke(Color.green,
                    style: StrokeStyle(
                        lineWidth: 8,
                        lineCap: .round,
                        dash: [0.1, 16]))
            .frame(width: 48, height: 48)
    }
}

スクリーンショット 2020-02-10 2.45.53.png

dashPhase

更改虚线的开始位置。默认值为0

让我们旋转

终于是动画了。
rotatioinEffect用于2D旋转动画。

rotationEffect(_:anchor:)

1
func rotationEffect(_ angle: Angle, anchor: UnitPoint = .center) -> some View

https://developer.apple.com/documentation/swiftui/text/3276966-rotationeffect
对于angle,指定旋转angular。
对于anchor,指定旋转中心。默认值为.center

angular

https://developer.apple.com/documentation/swiftui/angle
您可以将degreesradians传递给Angle。
由于这次将传递angular,因此我们将degrees作为参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
struct ContentView: View {
    var body: some View {
        Circle()
            .trim(from: 0, to: 0.6)
            .stroke(Color.green,
                    style: StrokeStyle(
                        lineWidth: 8,
                        lineCap: .round,
                        dash: [0.1, 16]))
            .frame(width: 48, height: 48)
            .rotationEffect(Angle(degrees: 180))
    }
}

围绕中心旋转180度。
スクリーンショット 2020-02-10 3.16.44.png

但这不是动画。
因此,我们将尝试随着时间的推移对其进行更改。

onAppear

首先,确定动画何时触发。
有各种各样的事情,例如按下按钮,滚动等,但是这次我将制作显示目标View的动画。
因此,请使用onAppear方法。

1
func onAppear(perform action: (() -> Void)? = nil) -> some View

使用View时,调用此方法将执行操作关闭。

https://developer.apple.com/documentation/swiftui/text/3276931-onappear

接下来是基本的动画处理。
这次,我们将使用withAnimation方法。

withAnimation

用指定的动画更新视图。
https://developer.apple.com/documentation/swiftui/3279151-withanimation
将要更改的状态变量与动画一起传递给闭包。

动画

<表格>

动画

说明

gif


<身体>

默认

默认

default.gif

线性

线性常数比

lineaer.gif

easeIn

逐渐加快

easeIn.gif

easeOut

逐渐放慢

easeOut.gif

easeInOut

起步较晚,在中间加速,最后再次变慢

easeInOut.gif


这一次,我希望您保持恒定的速度旋转,所以我将使用linear

您可以在

lienar方法中指定动画长度。
使用lienar(duration:)

@状态

设置状态变量。
通过在withAnimation闭包内切换此状态可以更改状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct ContentView: View {

    @State var isAnimation = false

    var body: some View {
        Circle()
            .trim(from: 0, to: 0.6)
            .stroke(Color.green,
                    style: StrokeStyle(
                        lineWidth: 8,
                        lineCap: .round,
                        dash: [0.1, 16]))

            .frame(width: 48, height: 48)
            .rotationEffect(Angle(degrees: self.isAnimation ? 360 : 0))
            .onAppear() {
                withAnimation(
                    Animation
                        .linear(duration: 1)) {
                            self.isAnimation.toggle()
                }
        }
    }
}

如果保持原样,则只能旋转一次结束,因此请使用repeatForever(autoreverses:)方法。

repeatForever(autoreverses:)

https://developer.apple.com/documentation/swiftui/animation/3263783-repeatforever

<表格>

自动反转




<身体>

true

true.gif

false.gif


指定false,因为您不必将其反转。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct ContentView: View {

    @State var isAnimation = false

    var body: some View {
        Circle()
            .trim(from: 0, to: 0.6)
            .stroke(Color.green,
                    style: StrokeStyle(
                        lineWidth: 8,
                        lineCap: .round,
                        dash: [0.1, 16]))

            .frame(width: 48, height: 48)
            .rotationEffect(Angle(degrees: self.isAnimation ? 360 : 0))
            .onAppear() {
                withAnimation(
                    Animation
                        .linear(duration: 1)
                        .repeatForever(autoreverses: true)) {
                            self.isAnimation.toggle()
                }
        }
    }
}

圆角矩形

等级

1
Gradient(colors: [.gray, .white])

<表格>

渐变

外观


<身体>

线性线性

スクリーンショット 2020-02-11 11.37.07.png

角圆

スクリーンショット 2020-02-11 11.15.46.png

激进中心主义

スクリーンショット 2020-02-11 11.37.49.png


.stroke方法中的Color.green更改为AngularGradient(gradient: Gradient(colors: [.gray, .white])
然后,您可以确认虚线的位置已如下图所示移动。

スクリーンショット 2020-02-11 2.06.21.png

然后更改StrokeStyledashPhase的值。

通过设置

dashPhase: 8

スクリーンショット 2020-02-11 2.07.40.png

画得很漂亮。

完成的源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import SwiftUI

struct ContentView: View {

    @State var isAnimation = false

    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 8)
                .frame(width: 200, height: 120, alignment: .center)
                .foregroundColor(Color.gray)

            VStack {
                Spacer()
                Circle()
                    .trim(from: 0, to: 0.6)
                    .stroke(AngularGradient(gradient: Gradient(colors: [.gray, .white]), center: .center),
                            style: StrokeStyle(
                                lineWidth: 8,
                                lineCap: .round,
                                dash: [0.1, 16],
                                dashPhase: 8))

                    .frame(width: 48, height: 48)
                    .rotationEffect(Angle(degrees: self.isAnimation ? 360 : 0))
                    .onAppear() {
                        withAnimation(
                            Animation
                                .linear(duration: 1)
                                .repeatForever(autoreverses: false)) {
                                    self.isAnimation.toggle()
                        }
                }

                Text("読み込み中")
                    .foregroundColor(.white)
                    .font(.system(size: 12, weight: .medium, design: .rounded))
                    .lineLimit(1)
                    .padding(.top)
                Spacer()
            }
        }
    }
}

挑战

我无法在strokestyke的破折号上击中动画;;
我想更改短划线的宽度,并使用easyOut制作动画,每个球都在动画的结尾附近以制作动画;;
请告诉我mm