Skip to content

Instantly share code, notes, and snippets.

@evandcoleman
Created December 26, 2022 20:37
Show Gist options
  • Save evandcoleman/88b40c9700283c39d8be3fd5aeb239d9 to your computer and use it in GitHub Desktop.
Save evandcoleman/88b40c9700283c39d8be3fd5aeb239d9 to your computer and use it in GitHub Desktop.
A button with a progress indicator for SwiftUI
//
// LoadingButton.swift
// App
//
// Created by Evan Coleman on 12/26/22.
//
import SwiftUI
struct LoadingButton<DefaultLabel: View, LoadingLabel: View>: View {
var action: () async -> Void
var label: DefaultLabel
var loadingLabel: LoadingLabel
@State private var isLoading: Bool = false
var body: some View {
Button(action: {
Task {
isLoading = true
await action()
isLoading = false
}
}) {
if isLoading {
loadingLabel
} else {
label
}
}
}
init(
action: @escaping () async -> Void,
label: () -> DefaultLabel,
loadingLabel: () -> LoadingLabel
) {
self.action = action
self.label = label()
self.loadingLabel = loadingLabel()
}
init(
_ label: String,
action: @escaping () async -> Void
) where DefaultLabel == Text, LoadingLabel == AnyView {
self.action = action
self.label = Text(label)
self.loadingLabel = AnyView(
ProgressView()
.progressViewStyle(.circular)
)
}
}
struct LoadingButton_Previews: PreviewProvider {
static var previews: some View {
VStack(spacing: 40) {
LoadingButton("Click Me") {
try? await Task.sleep(for: .seconds(2))
}
LoadingButton(
action: { try? await Task.sleep(for: .seconds(2)) }
) {
Text("Click Me")
.frame(width: 140)
} loadingLabel: {
ProgressView()
.progressViewStyle(.circular)
.frame(width: 140)
}
.buttonStyle(.bordered)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment