4
var body: some View {
    NavigationView {
        ZStack {
            Color(UIColor.systemGroupedBackground).edgesIgnoringSafeArea(.all)
            ScrollView(showsIndicators: false) {
                if #available(iOS 15.0, *) {
                    VStack {
                        if self.viewModel.forms.isEmpty && !self.viewModel.isLoading {
                            Text("No Forms Assigned")
                                .foregroundColor(Color.gray)
                                .padding(.vertical, 20)
                                .accessibility(label: Text("No forms assigned"))
                        }
                        if self.viewModel.isLoading {
                            ActivityIndicator(isAnimating: .constant(true), style: .large).padding(.top, 20)
                        }
                        noFormsScrollView
                        Spacer(minLength: 16).accessibility(hidden: true)
                    }
                    .refreshable {
                        self.refreshData()
                    }
                } else {
                    // Fallback on earlier versions
                }
            }
        }.navigationBarTitle("Forms", displayMode: .inline)
    }
}

I am trying to add pull to refresh on my ScrollView But it's not not working. I am wondering, what i am doing wrong.

Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Ferrakkem Bhuiyan
  • 2,741
  • 2
  • 22
  • 38

3 Answers3

5

Pull to refresh is only automatically available on List when using refreshable. To make any other view refreshable, you will need to write your own handler for that.

This StackOverflow example shows how to make pull to refresh work on a ScrollView.

Randall
  • 725
  • 9
  • 27
0

Complete SwiftUI Example

Simply create RefreshableScrollView in your project

public struct RefreshableScrollView<Content: View>: View {
    var content: Content
    var onRefresh: () -> Void

    public init(content: @escaping () -> Content, onRefresh: @escaping () -> Void) {
        self.content = content()
        self.onRefresh = onRefresh
    }

    public var body: some View {
        List {
            content
                .listRowSeparatorTint(.clear)
                .listRowBackground(Color.clear)
                .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
        }
        .listStyle(.plain)
        .refreshable {
            onRefresh()
        }
    }
}

then use RefreshableScrollView anywhere in your project

example:

RefreshableScrollView{
    // Your content
} onRefresh: {
    // do something you want
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Jishnu Raj T
  • 2,409
  • 1
  • 9
  • 13
  • Hello, it cannot support iOS 13+ since .refreshable { ) requires iOS 15+ – Elias Al Zaghrini Nov 09 '22 at 09:21
  • 1
    replace your completion to var onRefresh: @Sendable () async -> Void – George Heints Nov 15 '22 at 15:01
  • this is simply using a List, if you want to do that scrap this code and use List straight, also List will not work on horizontal scrollview !! – Shaybc Nov 27 '22 at 02:43
  • Thank you, that's exactly what I needed! ScrollView is refreshing fine on the device or simulator, but it's crashing the app when .refreshable called if refreshing logic also updates any Published var in the Observed viewModel. Have no idea why, but I've found that it is not crashing with List)) So, this solution is just so perfect and simple. I've just removed onRefresh from there which is unneeded because standard .refreshable works just fine cuz it's anyway an Environment. – bodich Jul 10 '23 at 12:55
0

Looks like in iOS 16+ you could do:

ScrollView {
    /// view
}
.refreshable {
    // refresh action
}

source: https://developer.apple.com/documentation/swiftui/refreshaction https://developer.apple.com/forums/thread/707510

The sources do say that this thing is 15+, but it does not seem to work on 15, even though it does not complain at compile time.

Adrian
  • 415
  • 4
  • 18