SwiftUI 創建Capsule Loading動畫
xcode 13.3.1, swift 5.5, iOS 15.4
2022-08-10
進度圈在很多地方都會用到,這篇我們會講講怎樣用SwiftUI Capsule Loading動畫。
1. 先創建一個小小的Capsule。
struct CapsuleExample : View {
var body: some View {
Capsule()
.stroke(.black, lineWidth: 5.0)
.frame(width: 20, height: 50)
}
}
2. 把Capsule向下移80個單位,並轉成一定的角度。
struct CapsuleExample : View {
let degree : Double = 30.0
var body: some View {
Capsule()
.stroke(.black, lineWidth: 5.0)
.frame(width: 20, height: 50)
.offset(y: 80)
.rotationEffect(.degrees(degree))
}
}
3. 把這個包裝 成一個Component組件 - CapsulePiece。
struct CapsulePiece : View {
let degree : Double
var body: some View {
Capsule()
.stroke(.black, lineWidth: 5.0)
.frame(width: 20, height: 50)
.offset(y: 80)
.rotationEffect(.degrees(degree))
}
}
struct CapsuleExample: View {
let degree : Double = 30.0
var body: some View {
CapsulePiece(degree: degree)
}
}
4. 覆用CapsulePiece組裝成一圈。
struct CapsulePiece : View {
let degree : Double
var body: some View {
Capsule()
.stroke(.black, lineWidth: 5.0)
.frame(width: 20, height: 50)
.offset(y: 80)
.rotationEffect(.degrees(degree))
}
}
struct CapsuleExample: View {
let numOfPieces = 15
var body: some View {
ZStack {
ForEach(0..<numOfPieces, id:\.self) { i in
CapsulePiece(degree: 360.0/Double(numOfPieces)*Double(i))
}
}
}
}
這個公式是計算每個CapsulePiece所需轉的角度:360.0/Double(numOfPieces)*Double(i)。
5. 為了可以做的動畫,需要在CapsulePiece增加一個變量selectFlag,以便控制其顯示或隱藏,以下例子我們只顯示第一個CapsulePiece控件,其他都隱藏。大家可以試試改變currentIndex的值去控制只顯示第幾個CapsulePiece控件。
struct CapsulePiece : View {
let degree : Double
let selectFlag : Bool
var body: some View {
Capsule()
.stroke(.black.opacity(selectFlag ? 1.0 : 0.0), lineWidth: 5.0)
.frame(width: 20, height: 50)
.offset(y: 80)
.rotationEffect(.degrees(degree))
}
}
struct CapsuleExample: View {
let numOfPieces = 15
@State var currentIndex = 0
var body: some View {
ZStack {
ForEach(0..<numOfPieces, id:\.self) { i in
CapsulePiece(degree: 360.0/Double(numOfPieces)*Double(i), selectFlag: i==currentIndex)
}
}
}
}
6. 變量currentIndex可以用來控制顯示第幾個CapsulePiece。只要增加一個Timer在隔一隔時間就把currentIndex增加一,就可以做成動畫。
struct CapsulePiece : View {
let degree : Double
let selectFlag : Bool
var body: some View {
Capsule()
.stroke(.black.opacity(selectFlag ? 1.0 : 0.0), lineWidth: 5.0)
.frame(width: 20, height: 50)
.offset(y: 80)
.rotationEffect(.degrees(degree))
}
}
struct CapsuleExample: View {
let numOfPieces = 15
@State var currentIndex = 0
var body: some View {
ZStack {
ForEach(0..<numOfPieces, id:\.self) { i in
CapsulePiece(degree: 360.0/Double(numOfPieces)*Double(i), selectFlag: i==currentIndex)
}
}
.onAppear(perform: animate)
}
func animate() {
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
currentIndex = (currentIndex + 1) % numOfPieces
}
}
}
7. 以下把控件CapsulePiece的顯示和隱藏交替做成漸變的方式。而做漸變動畫在SwiftUI只要告訴animation就可以,實作以下:
struct CapsulePiece : View {
let degree : Double
let selectFlag : Bool
var body: some View {
Capsule()
.stroke(.black.opacity(selectFlag ? 1.0 : 0.0), lineWidth: 5.0)
.frame(width: 20, height: 50)
.offset(y: 80)
.rotationEffect(.degrees(degree))
.animation(.linear(duration: 0.5), value: selectFlag)
}
}
struct CapsuleExample: View {
let numOfPieces = 15
@State var currentIndex = 0
var body: some View {
ZStack {
ForEach(0..<numOfPieces, id:\.self) { i in
CapsulePiece(degree: 360.0/Double(numOfPieces)*Double(i), selectFlag: i==currentIndex)
}
}
.onAppear(perform: animate)
}
func animate() {
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
currentIndex = (currentIndex + 1) % numOfPieces
}
}
}