A native, customizable SwiftUI refresh control

Last update: Jul 30, 2022

Refresher

A customizable, native Swift UI refresh control for iOS 14+

Why?

  • the native SwiftUI refresh control only works on iOS 15+
  • the native UIKit refresh control works with ugly wrappers, but has buggy behavior with navigation views
  • I needed a refresh control that could accomodate an overlay (such as appearing on top of a static image)
  • This one is very customizable

See it in action

If you want to see it in a real app, check out dateit

Usage

First add the package to your project.

import Refresher 

struct DetailsView: View {
    @State var refreshed = 0

    var body: some View {
        ScrollView {
            Text("Details!")
            Text("Refreshed: \(refreshed)")
        }
        .refresher { done in // Called when pulled to refresh
            await Task.sleep(seconds: 2)
            refreshed += 1
        }
    }
}

Features

  • async/await compatible - even on iOS 14
  • completion callback also supported for DispatchQueue operations
  • .default and .system styles (see below for details)
  • customizable refresh spinner (see below for example)

Examples and usage

See: Examples for a full sample project with multiple implementations

Navigation view

Navigation

Refresher plays nice with both Navigation views and navigation subviews.

Subview

Detail view with overlay

Refresher supports an overlay mode to show a refresh indicator over fixed position content

.refresher(overlay: true)

Overlay

System style

Refresher's default animation is designed to be more flexible that the system animation style. If you want Refresher to behave more like they system refresh control, you can change the style:

.refresher(style: .system) { done in

System

Customization

Refresher can take a custom spinner view. Your custom view will get a binding instances of the refresher state that contains useful properties for managing animations and translations. Here is a custom spinner that shows an emoji:

public struct EmojiRefreshView: View {
    @Binding var state: RefresherState
    @State private var angle: Double = 0.0
    @State private var isAnimating = false
    
    var foreverAnimation: Animation {
        Animation.linear(duration: 1.0)
            .repeatForever(autoreverses: false)
    }
    
    public var body: some View {
        VStack {
            switch state.mode {
            case .notRefreshing:
                Text("🤪")
                    .onAppear {
                        isAnimating = false
                    }
            case .pulling:
                Text("😯")
                    .rotationEffect(.degrees(360 * state.dragPosition))
            case .refreshing:
                Text("😂")
                    .rotationEffect(.degrees(self.isAnimating ? 360.0 : 0.0))
                        .onAppear {
                            withAnimation(foreverAnimation) {
                                isAnimating = true
                            }
                    }
            }
        }
        .scaleEffect(2)
    }
}

Add the custom refresherView:

.refresher(refreshView: EmojiRefreshView.init ) { done in

Custom

Completion handler

If you prefer to call a completion to stop the refresher:

.refresher(style: .system) { done in
    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
        refreshed += 1
        done()
    }
}

GitHub

https://github.com/gh123man/SwiftUI-Refresher
You might also like...

VerticalTabView is a native way to display paged vertical content in SwiftUI.

VerticalTabView 🔝 VTabView is a native way to display paged vertical content in SwiftUI. To work it makes use of the new iOS 14 TabView PageTabViewSt

Jul 28, 2022

A completely native Discord client for macOS built 100% in Swift and SwiftUI

Swiftcord A completely native Discord client for macOS built 100% in Swift and SwiftUI This project aims to create a fully functional native Discord c

Aug 9, 2022

📱 Guideo - Native iOS App crafted with Swift and SwiftUI

📱 Guideo - Native iOS App crafted with Swift and SwiftUI

Guideo An awesome iOS Native App 📱 About Guideo App wire-framed and crafted from scratch by a team of 4. Our final project of the  Apple Foundation

May 23, 2022

Native iOS app built in SwiftUI, displays a collection of user's books.

Native iOS app built in SwiftUI, displays a collection of user's books.

May 23, 2022

Native Jellyfin Client for iOS and tvOS

Native Jellyfin Client for iOS and tvOS

Swiftfin Swiftfin is a modern client for the Jellyfin media server. Redesigned in Swift to maximize direct play with the power of VLC and look native

Aug 5, 2022

Native and encrypted password manager for iOS and macOS.

Native and encrypted password manager for iOS and macOS.

Open Sesame Native and encrypted password manager for iOS and macOS. What is it? OpenSesame is a free and powerful password manager that lets you mana

Aug 6, 2022

Seaglass is a truly native macOS client for Matrix. It is written in Swift and uses the Cocoa user interface framework.

Seaglass is a truly native macOS client for Matrix. It is written in Swift and uses the Cocoa user interface framework.

Seaglass is a truly native macOS client for Matrix. It is written in Swift and uses the Cocoa user interface framework.

Jan 17, 2022

Provenance is a native macOS application that interacts with the Up Banking Developer API to display information about your bank accounts, transactions, categories, tags and more.

Provenance Provenance is a native macOS application that interacts with the Up Banking Developer API to display information about your bank accounts,

Jul 29, 2022

iOS framework for making Turbo native apps

Turbo Native for iOS Note: The Hotwire frameworks are presented in beta form. We're using them all in production with HEY, but expect that significant

Aug 5, 2022
Comments
  • 1. Refresh status binding

    Some kind of binding to have a programmatic ability to refresh content or just set view to refresh state

    My use case is for when you refresh in subview but navigate back and navigate again to subview but refresh is no longer show Task is launched in global ObservableObject to avoid stopping or losing progress since it's refreshing a lot of item

    Reviewed by AzSiAz at 2022-06-01 09:29
Control Room : a macOS app that lets you control the simulators for iOS, tvOS, and watchOS
Control Room : a macOS app that lets you control the simulators for iOS, tvOS, and watchOS

Control Room is a macOS app that lets you control the simulators for iOS, tvOS, and watchOS – their UI appearance, status bar configuration, and more.

Nov 30, 2021
A weather app developed in React Native. It is the React Native version of SwiftWeather.
A weather app developed in React Native. It is the React Native version of SwiftWeather.

ReactNativeWeather A weather app developed in React Native. It is the React Native version of SwiftWeather How to run the app Install react-native If

Jun 7, 2022
Control RGB stripes with SwiftUI+Combine
Control RGB stripes with SwiftUI+Combine

An experiment app for RGB stripe control. Written in SwiftUI+Combine

Jul 1, 2022
IdleTimerState - Control the idle timer for the SwiftUI app

IdleTimerState Control the idle timer for the SwiftUI app. import SwiftUI import

Feb 3, 2022
A customizable Snapping Drawer à la Apple Maps.

 100% in SwiftUI.
A customizable Snapping Drawer à la Apple Maps.

 100% in SwiftUI.

Snap A customizable Snapping Drawer à la Apple Maps, Apple Music, Stocks, Overcast, etc.. 100% in SwiftUI This is heavily inspired by Rideau and based

Jul 31, 2022
Reusable & customizable SwiftUI settings sheet as a Swift package

PackAPrefPane Reusable & customizable SwiftUI settings sheet as a Swift package Features Swift package 100% Swift 99% SwiftUI Simple design Lightweigh

Jul 19, 2022
BeezyLight.app✦ tiny macOS app to control a usb-connected light

BeezyLight.app✦ tiny macOS app to control a usb-connected light

Jul 11, 2022
ReactionButton is a control that allows developers to add this functionality to their apps in an easy way.
 ReactionButton is a control that allows developers to add this functionality to their apps in an easy way.

Since Facebook introduced reactions in 2016, it became a standard in several applications as a way for users to interact with content. ReactionButton is a control that allows developers to add this functionality to their apps in an easy way.

Mar 12, 2022
Demonstration of using UIWindowScene and SwiftUI to provide a native-looking Mac preferences window in Catalyst
Demonstration of using UIWindowScene and SwiftUI to provide a native-looking Mac preferences window in Catalyst

CatalystPrefsWindow Ever wondered how to create a more Mac-like preferences window for Catalyst? Perhaps Settings Bundles are too limiting for the kin

Aug 10, 2022
A native SoundCloud app for macOS, written in SwiftUI
A native SoundCloud app for macOS, written in SwiftUI

Nuage A native SoundCloud app for macOS, written in SwiftUI About Nuage is an independent and open-source project to build a native SoundCloud client

Jul 30, 2022