Skip to content

Instantly share code, notes, and snippets.

@MaxenceMottard
Last active June 18, 2023 02:35
Show Gist options
  • Save MaxenceMottard/2f451277edeac4220d6f5c6d54215fe5 to your computer and use it in GitHub Desktop.
Save MaxenceMottard/2f451277edeac4220d6f5c6d54215fe5 to your computer and use it in GitHub Desktop.
import SwiftUI
struct RefreshableScrollView<Content: View>: View {
@State private var isRefreshing = false
@State private var initialValue: CGFloat = 50
private var threshold: CGFloat = 100
let axes: Axis.Set
let showsIndicators: Bool
let onRefresh: () async -> Void
let content: () -> Content
init(
_ axes: Axis.Set = .vertical,
showsIndicators: Bool = true,
onRefresh: @escaping () async -> Void,
@ViewBuilder content: @escaping () -> Content
) {
self.axes = axes
self.showsIndicators = showsIndicators
self.content = content
}
var body: some View {
ZStack(alignment: .top) {
ScrollView(axes, showsIndicators: showsIndicators) {
GeometryReader { reader -> Color in
let offset = reader.frame(in: .global)
DispatchQueue.main.async {
if offset.minY > (initialValue + threshold) {
withAnimation {
isRefreshing = true
}
}
}
return Color.clear
}
.frame(height: 1)
.offset(y: -10)
content()
.padding(.top, isRefreshing ? 40 : 0)
}
ProgressView()
.hidden(when: !isRefreshing)
.padding(.vertical, 13)
}
.onChange(of: isRefreshing) { newValue in
guard newValue else { return }
Task {
await onRefresh()
withAnimation {
isRefreshing = false
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment