Reputation: 1146
I have a refreshable Scroll View using .refreshable
and it works exactly how I need it to except for the loading view. How can I hide or replace that loading wheel?
.refreshable {
Task {
// Reload
}
}
Upvotes: 5
Views: 3742
Reputation: 126
I created extension for ScrollView to mimic native refreshable behaviour.
Example of usage:
ScrollView {
VStack {
ForEach(0...100, id: \.self) { index in
Text("row \(index)")
.padding()
.frame(width: .infinity)
}
}
.frame(maxWidth: .infinity)
}
.refreshable {
// asyncronously refresh your data here
try? await Task.sleep(nanoseconds: 2_000_000_000)
}
Extension implementation:
public extension ScrollView {
func refreshable(onRefresh: @escaping RefreshAction) -> some View {
ScrollWithRefreshView(content: { self },
onRefresh: onRefresh)
}
}
Custom ScrollView implementation to use in the extension. Don't forget to replace CustomRefreshView with your custom refresh view:
import SwiftUI
public typealias RefreshAction = () async -> ()
struct RefreshViewOffsetKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value += nextValue()
}
}
public struct ScrollWithRefreshView<Content: View>: View {
let content: Content
let onRefresh: RefreshAction
@State private var isRefreshing: Bool = false
public init(@ViewBuilder content: () -> Content,
onRefresh: @escaping RefreshAction) {
self.onRefresh = onRefresh
self.content = content()
}
private let amountToPullBeforeRefreshing: CGFloat = 180
public var body: some View {
ScrollView {
if isRefreshing {
// PUT YOUR CUSTOM VIEW HERE
CustomRefreshView()
}
content
.overlay(GeometryReader { geo in
let currentScrollViewPosition = -geo.frame(in: .global).origin.y
if currentScrollViewPosition < -amountToPullBeforeRefreshing && !isRefreshing {
Color.clear.preference(key: RefreshViewOffsetKey.self, value: -geo.frame(in: .global).origin.y)
}
})
}
.onPreferenceChange(RefreshViewOffsetKey.self) { scrollPosition in
if scrollPosition < -amountToPullBeforeRefreshing && !isRefreshing {
isRefreshing = true
Task {
await onRefresh()
isRefreshing = false
}
}
}
}
}
Upvotes: 1