# Loading Indicators

[SwiftUI](https://lochiwei.gitbook.io/ios/swiftui) ⟩ [Animations](https://lochiwei.gitbook.io/ios/swiftui/anim) ⟩ [examples](https://lochiwei.gitbook.io/ios/swiftui/anim/examples) ⟩ loading indicators

{% tabs %}
{% tab title="👁️ 預覽" %}
{% embed url="<https://youtu.be/Imd4uUQOBSs>" %}

```swift
struct ContentView: View {
    @State private var isComplete = false
    var body: some View {
        VStack {
            HStack {
                TapView()                // ⭐️ tap to animate
                CircularLoadingView()    // ⭐️ circular loading indicator
            }
            .frame(height: 100)
            LinearLoadingView()          // ⭐️ linear loading indicator
                .padding(.top, 40)
        }
        .padding()
    }
}
```

{% endtab %}

{% tab title="tap" %}

```swift
struct TapView: View {
    // ⭐️ 1. animation states (true/false)
    @State private var isComplete = false
    var body: some View {
        ZStack {
            Circle()
                .fill(Color(.systemGray6))
            Circle()
                // ⭐️ 2. things to animate (shape path parameter)
                .trim(from: 0, to: isComplete ? 1 : 0.1)
                .stroke(Color.green, lineWidth: 14)
                .rotationEffect(.degrees(-90))
            Text("Tap")
                .foregroundColor(.secondary)
        }
        // ⭐️ 4. event to trigger animation (tap)
        .onTapGesture {
            // ⭐️ 3. animation curve (.default)
            withAnimation { isComplete.toggle() }
        }
    }
}
```

{% endtab %}

{% tab title="circular" %}

```swift
struct CircularLoadingView: View {
    // ⭐️ 1. animation states (true/false)
    @State private var isLoading = false    
    var body: some View {
        VStack {
            ZStack {
                Circle()
                    .stroke(.orange, lineWidth: 14)
                Circle() 
                    .trim(from: 0, to: 0.7) 
                    .stroke(.pink, lineWidth: 10) 
                    .frame(width: 100, height: 100)
                    // ⭐️ 2. things to animate (rotation angle)
                    .rotationEffect(.degrees(isLoading ? 360 : 0))
                    // ⭐️ 3. animation curve (.linear)
                    .animation(.linear(duration: 2).repeatForever(autoreverses: false)) 
                    // ⭐️ 4. event to trigger animation (on appear)
                    .onAppear { 
                        self.isLoading = true 
                    }
                Text("Loading")
                    .foregroundColor(.secondary)
            }
        }
    }
}
```

{% endtab %}

{% tab title="linear" %}

```swift
struct LinearLoadingView: View {
    // ⭐️ 1. animation states (true/false)
    @State private var isLoading = false
    var body: some View {
        VStack {
            Text("Loading")
                .foregroundColor(.secondary)
            ZStack {
                Capsule()
                    .fill(Color(.systemGray5))
                    .frame(width: 250, height: 8)
                
                Capsule()
                    .fill(.blue) 
                    .frame(width: 30, height: 6)
                    // ⭐️ 2. things to animate (offset)
                    .offset(x: isLoading ? 110 : -110)
                    // ⭐️ 3. animation curve (.linear)
                    .animation(.linear(duration: 1).repeatForever())
                    // ⭐️ 4. event to trigger animation (on appear)
                    .onAppear { 
                        self.isLoading = true
                    }
            }
        }
    }
}
```

{% endtab %}

{% tab title="dots" %}
{% embed url="<https://youtu.be/7m4Hd32590Y>" %}

⬆️ 需要： [ext](https://lochiwei.gitbook.io/ios/swiftui/view/layout/frame/ext "mention"), [floating-+-int](https://lochiwei.gitbook.io/ios/swift/type/category/basic/numbers/floating-point/floating-+-int "mention")

👥 相關： [delay](https://lochiwei.gitbook.io/ios/swiftui/anim/delay "mention")

```swift
struct DotsLoadingIndicator: View { 
    // ⭐️ 1. animation states (true/false)
    @State private var isLoading = false
    var body: some View { 
        HStack { 
            ForEach(0..<5) { i in 
                Circle() 
                    .frame(8)                 // 🌀 View+
                    .foregroundColor(.green) 
                    // ⭐️ 2. things to animate (scale)
                    .scaleEffect(isLoading ? 0.2 : 1)
                    // ⭐️ 3. animation curve (.linear)
                    .animation(
                        .linear(duration: 0.8)
                            .repeatForever()
                            // ⭐️ delay
                            .delay(0.2 * i)    // 🌀 FloatingPoint+
                    )
            }
        }
        // ⭐️ 4. event to trigger animation (on appear)
        .onAppear { isLoading = true }
    }
}
```

{% endtab %}

{% tab title="📗 參考" %}

* [x] [Mastering SwiftUI](https://www.appcoda.com/swiftui/), Ch. 9: Animations & Transitions ⟩
  * [x] Loading Indicator (p. 198)
  * [x] Delaying an Animation (p.207)
    {% endtab %}

{% tab title="👥 相關" %}

* compare: [timerview-scheduledtimer](https://lochiwei.gitbook.io/ios/swift/scope/framework/built-in-frameworks/combine/timer/timerview-scheduledtimer "mention") - progress indicator.
  {% endtab %}
  {% endtabs %}
