-1

I have set a .refreshable modifier on one of my views (attached to a VStack). This view has NavigationLinks to other pages, but unexpectedly the refreshable still works in the next pages on the NavigationStack.

i.e. I can still pull to refresh in any page that was linked from the first page where I declared the .refreshable...

I would like this .refreshable to apply only to the first page, and not to the rest of the pages.

How do I do that, and why does it behave like that in the first place?

The code on the first View/page looks like this:

 VStack {
    NavigationStack {
        List {
            //Some code with list elements
        }
    }
}
.refreshable {
    await vm.loadUserStories(getUrl: url)
HangarRash
  • 7,314
  • 5
  • 5
  • 32
Ori C.
  • 61
  • 7

3 Answers3

2

16.4 will fix this bug

Fixed: Refreshable modifiers applied to lists will no longer also apply to lists or scroll views within the content of that list. Re-apply a refreshable modifier to the content of the list if this is desired behavior. (102052575)

iOS & iPadOS 16.4 Beta Release Notes

malhal
  • 26,330
  • 7
  • 115
  • 133
1

From the .refreshable documentation:

Apply this modifier to a view to set the refresh value in the view’s environment to a RefreshAction instance that uses the specified action as its handler.

So the modifier puts your closure into the SwiftUI environment. That's why all your pages use it.

Reading on:

For example, when you apply this modifier on iOS and iPadOS to a List, the list enables a standard pull-to-refresh gesture that refreshes the list contents.

So the answer is, put the modifier directly on the List instead of on the NavigationStack. Then only the environment of the List (and its subviews) will contain the RefreshAction, and it won't be visible to your other pages.

VStack {
    NavigationStack {
        List {
            //Some code with list elements
        }
        .refreshable {
            await vm.loadUserStories(getUrl: url)
        }
    }
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • I tried to put it first on the List, but my next views are NavigationLinks from within the List, so every new page is still 'refreshable' which I am trying to avoid. So I move it up to the VStack, and it still does that. Isn't there a way to make the refreshable just work for the page its in? – Ori C. Feb 23 '23 at 18:45
  • What is your deployment target? iOS 16? iOS 15? – rob mayoff Feb 23 '23 at 18:50
  • It's currently set for 16.0 (would be nice to support 15 as well though) – Ori C. Feb 23 '23 at 18:52
0

It's better to put the NavigationStack to be the first container not the VStack like this

struct ContentView: View {
   var body: some View {
    NavigationStack {
        VStack {
            List {
                NavigationLink(destination: someView) {
                    Text("Hello, world!")
                }
                NavigationLink(destination: Text("Hello, world!")) {
                    Text("Hello, world!")
                }
                NavigationLink(destination: Text("Hello, world!")) {
                    Text("Hello, world!")
                }
                
                
            }
            .refreshable {
                print("yes")
            }
        }
        
    }
}

  var someView: some View {
      return VStack {
          List {
              Text("Hello, world!")
              Text("Hello, world!")
          }
      }
  }
 
}

this should work, you can use NavigationView if you you want to support iOS versions less than iOS 16 but it's deprecated in iOS 16+

Ahmed Mohiy
  • 190
  • 1
  • 7