Adding Pull-to-Refresh in SwiftUI with refreshable

AsyncLearn
2 min readFeb 19, 2024

Sometimes, it is necessary to provide users with the ability to update a list through gestures. On Apple platforms, it is common to use the “pull-to-refresh” gesture. This gesture involves pulling down on a view, usually a List, to refresh the data.

To implement this behavior in SwiftUI, we use the refreshable(action:) modifier. This modifier allows us to provide a closure that will be executed when the user performs the gesture.

Let’s see an example:

struct TaskListView: View {
private var todos: [TodoItem] = [
.init(content: "Clean house"),
.init(content: "Cook"),
.init(content: "Go to work")
]

var body: some View {
NavigationStack {
List {
ForEach(todos) { todoItem in
Text(todoItem.content)
}
}
.refreshable {
await refresh()
}
.navigationTitle("My Tasks")
}
}

private func refresh() async {
try? await Task.sleep(nanoseconds: 1_000_000)
}
}

This code presents a List that displays a list of Text elements. The refreshable modifier is applied to this List, and it contains a closure that executes the asynchronous task refresh.

Simulator showing how the progress indicator appears.

It is important to note that it is not necessary to wrap the asynchronous code with Task, as the closure expected in refreshable can be async, as shown in its definition:

public func refreshable(
action: @escaping @Sendable () async -> Void
) -> some View

The refresh Environment Variable

When we use refreshable, the content of the closure is stored in an environment variable. Therefore, we can access it using the following code:

import SwiftUI

struct MyChildView: View {
@Environment(\.refresh) private var refreshFunction
var body: some View {
Button("Run") {
await refreshFunction()
}
}
}

It is crucial to remember that this is only possible if the view where we use the environment variable is a child view of the view where we defined refreshable previously.

If you want to read the Spanish version of this article, you can find it here: https://asynclearn.com/blog/pull-to-refresh-swiftui/

--

--

AsyncLearn

Stay up-to-date in the world of mobile applications with our specialised blog.