Swiftpack.co - globulus/swiftui-pull-to-refresh as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
globulus/swiftui-pull-to-refresh
Pull to refresh functionality for any ScrollView in SwiftUI!
.package(url: "https://github.com/globulus/swiftui-pull-to-refresh.git", from: "1.1.1")

SwiftUIPullToRefresh

Pull to refresh is a common UI pattern, supported in UIKit via UIRefreshControl. (Un)surprisingly, it's also unavailable in SwiftUI prior to version 3, and even then it's a bit lackluster.

This package contains a component - RefreshableScrollView - that enables this functionality with any ScrollView. It also doesn't rely on UIViewRepresentable, and works with any iOS version. The end result looks like this:

in action

Features

  • Works on any ScrollView.
  • Customizable progress indicator, with a default RefreshActivityIndicator spinner that works on any SwiftUI version.
  • Specify refresh operation and choose when it ends.
  • Support for Swift 5.5 async blocks.
  • Compatibility refreshCompat modifier to deliver a drop-in replacement for iOS 15 refreshable.

Installation

This component is distrubuted as a Swift package. Just add this URL to your package list:

https://github.com/globulus/swiftui-pull-to-refresh

Sample usage

Bread & butter

struct TestView: View {
  @State private var now = Date()

  var body: some View {
     RefreshableScrollView(onRefresh: { done in
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
          self.now = Date()
          done()
        }
      }) {
        VStack {
          ForEach(1..<20) {
            Text("\(Calendar.current.date(byAdding: .hour, value: $0, to: now)!)")
               .padding(.bottom, 10)
           }
         }.padding()
       }
     }
   }
}

Custom progress view

RefreshableScrollView(onRefresh: { done in
  DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
    self.now = Date()
    done()
  }
},
progress: { state in // HERE
   if state == .waiting {
       Text("Pull me down...")
   } else if state == .primed {
       Text("Now release!")
   } else {
       Text("Working...")
   }
}) {
  VStack {
    ForEach(1..<20) {
      Text("\(Calendar.current.date(byAdding: .hour, value: $0, to: now)!)")
         .padding(.bottom, 10)
     }
   }.padding()
}

Using async block

 RefreshableScrollView(action: { // HERE
     await Task.sleep(3_000_000_000)
     now = Date()
 }, progress: { state in
     RefreshActivityIndicator(isAnimating: state == .loading) {
         $0.hidesWhenStopped = false
     }
 }) {
    VStack {
      ForEach(1..<20) {
        Text("\(Calendar.current.date(byAdding: .hour, value: $0, to: now)!)")
           .padding(.bottom, 10)
       }
     }.padding()
   }
 }

Compatibility mode

  VStack {
      ForEach(1..<20) {
      Text("\(Calendar.current.date(byAdding: .hour, value: $0, to: now)!)")
        .padding(.bottom, 10)
    }
  }
  .refreshableCompat { done in // HERE
      DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        self.now = Date()
        done()
      }
  } progress: { state in
      RefreshActivityIndicator(isAnimating: state == .loading) {
          $0.hidesWhenStopped = false
      }
  }

Recipe

Check out this recipe for in-depth description of the component and its code. Check out SwiftUIRecipes.com for more SwiftUI recipes!

Changelog

  • 1.1.1 - Added showsIndicators to allow for showing/hiding ScrollView indicators.
  • 1.1.0 - Added ability to specify custom progress view, iOS 15 support, async block support and compatibility mode.
  • 1.0.0 - Initial release.

GitHub

link
Stars: 32
Last commit: 4 weeks ago

Ad: Job Offers

iOS Software Engineer @ Perry Street Software
Perry Street Software is Jack’d and SCRUFF. We are two of the world’s largest gay, bi, trans and queer social dating apps on iOS and Android. Our brands reach more than 20 million members worldwide so members can connect, meet and express themselves on a platform that prioritizes privacy and security. We invest heavily into SwiftUI and using Swift Packages to modularize the codebase.

Submit a free job ad (while I'm testing this). The analytics numbers for this website are here.

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics