A native, customizable SwiftUI refresh control

Overview

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()
    }
}
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

📱 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

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

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.

Riddler is a riddle game built as a native iOS app in Swift using SwiftUI
Riddler is a riddle game built as a native iOS app in Swift using SwiftUI

Riddler is a riddle game built as a native iOS app in Swift using SwiftUI. It includes 50 challenging riddles with hints for when you get stuck. The game tracks your stats so you can compare your performance against your friends, and see who can answer all 50 riddles the quickest.

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

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

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.

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,

Comments
  • Refresh status binding

    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

    opened by AzSiAz 0
Releases(1.0.10)
Owner
Brian Floersch
Brian Floersch
Pull to refresh in SwiftUI for List, NavigationView

SwiftUI-PullToRefresh Pull to refresh implementation in SwiftUI for List and NavigationView This article helped me a lot: https://swiftui-lab.com/scro

Andras Samu 381 Nov 24, 2022
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

Jake Lin 22 Jun 7, 2022
Control RGB stripes with SwiftUI+Combine

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

Artem Novichkov 21 Nov 15, 2022
IdleTimerState - Control the idle timer for the SwiftUI app

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

null 1 Feb 3, 2022
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

Mathias Quintero 632 Jan 4, 2023
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

W1W1-M 9 Nov 6, 2022
BeezyLight.app✦ tiny macOS app to control a usb-connected light

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

null 2 Jul 11, 2022
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.

Jorge Ovalle 305 Oct 11, 2022
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

Steven Troughton-Smith 148 Dec 27, 2022
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

Laurin Brandner 203 Dec 30, 2022