I have a struct containing a List and within that list some other struct Views. Some of those structs contain horizontal scrollViews. When I assign to the List .refreshable that modifier applies to all scrollViews within that list. So all horizontal scrollViews have vertical refreshable properties which is not what I want. Any ideas on how to approach this? Thank you
Asked
Active
Viewed 342 times
0
-
You could try to nest the scrollViews in groups or get the scrollViews in separated structs.?! – FrugalResolution Sep 27 '22 at 17:40
-
@Felix thank you for your reply. They are in different structs – snksnk Sep 27 '22 at 17:41
-
The secret behind SwiftUI is that a struct with all it's content gets rerendered when a value like a @State object changes. So When you refresh one scrollView of the main struct and the data is based in the main struct it will render all subviews. – FrugalResolution Sep 27 '22 at 17:43
-
@Felix I understand that but I don't get it why a scrollView in a separate struct gets the main List's modifier properties. Very weird issue and no idea how to solve it. No articles online either.. – snksnk Sep 27 '22 at 17:52
-
@flashspys I ended up using introspect scrollView in my nested views with isDirectionalLockEnabled. But since I asked there was another answer here: https://stackoverflow.com/questions/74042635/nested-scrollview-in-a-list-refreshable-strange-behaviour-in-ios-16 – snksnk Oct 21 '22 at 12:14
1 Answers
0
The refreshable modifier puts a refreshable action in the environment. If it is cleared out, it should prevent the child scroll views from picking it up. Here's a pure SwiftUI way of doing it. This is wrapped up into a convenient modifier but all that is necessary is to clear out the refresh key from the environment. .environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
public struct RefreshableBlocker: ViewModifier {
public func body(content: Content) -> some View {
if let refreshKeyPath = \EnvironmentValues.refresh as? WritableKeyPath<EnvironmentValues, RefreshAction?> {
content.environment(refreshKeyPath, nil)
} else {
content
}
}
}
public extension View {
func blockPullToRefresh() -> some View {
self.modifier(RefreshableBlocker())
}
}
Just put this somewhere above the child scrollviews in the view hierarchy. You should be able switch List for ScrollView in the example below.
ScrollView {
LazyVStack(spacing: 12) {
ForEach(items, id: \.self) { item in
ItemCell(data: item).blockPullToRefresh()
}
}
}

Sam Corder
- 5,374
- 3
- 25
- 30