SwiftUI refreshable modifier in iOS 15
SwiftUI is a comparatively new UI framework but still gaining popularity amongst the developers. It is missing few controls which developers are using with UIKit. Apple will keep adding the missing UI control like UIRefreshControl and keep adding more to the archery.
The best illustration is searchable.
To learn searchable do this blog.
In WWDC 2021, with an iOS 15 and SwiftUI 3, they have added a refreshable modifier. It marks this view as refreshable which is attached with this modifier.
When you apply this modifier on iOS and iPadOS to a scrollable view like List, the view provides a standard way for the user to refresh the content. When the user drags the top of the scrollable content area downward, the view reveals a refresh control and executes the provided action.
Lets learn by a code!!!
Before directly jumping into a View. Let’s have data to be populated into a View.
ViewModel to fetch the post information from a server.
Lets have a list view to display the Posts.
Posts are getting fetched and appear in the list.
You can see we have a total of 500 posts on launch.
Now the question arises, How do we load the next set of posts? or How do the users will refresh the posts?
The best way to refresh the list is to pull to refresh.
Until now, pull to refresh control was unavailable. But we have it now, and it is simple to add as the MANTRA of SwiftUI is Better Apps. Less Code.
func refreshable(action: @escaping () async -> Void) -> some View
action
An async action that SwiftUI executes when the user performs a standard gesture. Use this action to initiate an update of model data that the modified view displays. Use an await
expression inside the action. SwiftUI shows a refresh indicator, which stays visible for the duration of the awaited operation.
Just add the refreshable modifier to the List and call the loadPost()
Here is the final result…
It looks like the refresh indicator is getting invisible before new data gets load. And there are no API to control it.
In UIKit, we use to handle the visibility of the refresh control with the beginRefreshing() and keep showing indicator until we call endRefreshing().
These methods/modifiers are not available with SwiftUI’s new refreshable modifier, and it probably is handling the visibility of the refresh indicator based on the action execution added in a refreshable modifier.
Apple has used the new Swift feature, async/await, to automatically control it.
My high-level understanding on how it is working?
- When the user pull-down the view with the refreshable modifier. It makes the refresh indicator visible. (Similar to the beginRefreshing())
- Then it starts executing the code inside the action block of refreshable. This action should be with await/async.
- It will wait till the async operation is finished on which we are waiting.
- Once the async operation is complete. It remove/hide the refresh control (Similar to the endRefreshing())
NOTE: I am not quite aware of the async/await feature. I just explored it for this blog. However, soon will explore async/await and actor in depth.
One more change, Instead of using onAppear modifier we have used a task modifier that helps to perform when this view appears and The task will be cancelled when this view disappears.
Other SwiftUI 15 blogs you might want to take a look,
- SwiftUI iOS 15 searchable modifier
- SwiftUI iOS 15 swipeActions modifier