30
loading...
This website collects cookies to deliver better user experience
List(posts) { post in
PostView(post: post)
}
.refreshable {
await refreshListAsync()
}
func refreshable(action: @escaping () async -> Void) -> some View
struct ScrollViewPullRefresh<Content:View>: View {
@Environment(\.refresh) var refreshAction: RefreshAction?
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
VStack {
if isRefreshing {
ProgressView()
}
}
GeometryReader { geometry in
ScrollView {
content()
.anchorPreference(key: OffsetPreferenceKey.self, value: .top) {
geometry[$0].y
}
}
.onPreferenceChange(OffsetPreferenceKey.self) { offset in
if offset > threshold && isRefreshing == false {
if let action = refreshAction {
Task {
isRefreshing = true
await action()
withAnimation {
isRefreshing = false
}
}
}
}
}
}
}
private var content: () -> Content
@State private var isRefreshing = false
private let threshold = 50.0
}
@Environment(\.refresh) var refreshAction: RefreshAction?
public struct RefreshAction {
...
public func callAsFunction() async
}
.onPreferenceChange(OffsetPreferenceKey.self) { offset in
if offset > threshold && isRefreshing == false {
if let action = refreshAction {
Task {
isRefreshing = true
await action()
withAnimation {
isRefreshing = false
}
}
}
}
}
var body: some View {
ScrollViewPullRefresh {
VStack {
ForEach(posts) { post in
PostView(post: post)
}
}
}
.task {
posts = await getPosts()
}
.refreshable {
posts = await shufflePosts()
}
}
private func shufflePosts() async -> [Post] {
await Task.sleep(2_000_000_000)
return viewModel.allPosts.shuffled()
}
struct RefreshableView: View {
@ObservedObject var viewModel: ListViewModel
@Environment(\.refresh) var refreshAction: RefreshAction?
var body: some View {
VStack {
Button {
if let action = refreshAction {
Task {
await action()
}
}
} label: {
Image(systemName: "arrow.counterclockwise")
}
ScrollView {
ForEach(viewModel.beers) { beer in
HStack {
CustomImageView(url: URL(string: beer.imageUrl),
placeHolder: Image(systemName: "xmark.octagon"))
.frame(width: 100, height: 100)
Text(beer.name)
Spacer()
}
}
}
}
}
}