# Loading Indicators

[SwiftUI](/ios/swiftui.md) ⟩ [Animations](/ios/swiftui/anim.md) ⟩ [examples](/ios/swiftui/anim/examples.md) ⟩ 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>" %}

⬆️ 需要： [view + .frame()](/ios/swiftui/view/layout/frame/ext.md), [floating +−⨉÷ int](/ios/swift/type/category/basic/numbers/floating-point/floating-+-int.md)

👥 相關： [delay](/ios/swiftui/anim/delay.md)

```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)](/ios/swift/scope/framework/built-in-frameworks/combine/timer/timerview-scheduledtimer.md) - progress indicator.
  {% endtab %}
  {% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lochiwei.gitbook.io/ios/swiftui/anim/examples/loading-indicators.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
