Reading time: 1 min

This recipe shows how to disable scrolling in a ScrollView or List, while still allowing interactions with its subviews.

The end result looks like this:

preview

The trick is to use a DragGesture with minimumDistance of zero, which will then intercept scrolling touches, while still allowing taps and long presses on the subviews. Here's the code:

extension View {
  @ViewBuilder func scrollEnabled(_ enabled: Bool) -> some View {
    if enabled {
      self
    } else {
      simultaneousGesture(DragGesture(minimumDistance: 0),
                          including: .all)
    }
  }
}

And here's how to use it with a List or ScrollView:

  @State private var scrollEnabled = true

  var body: some View {
    VStack {
      Toggle("Scroll enabled", isOn: $scrollEnabled)

      List(1..<50) { index in
        Text("Row \(index)")
      }
      .scrollEnabled(scrollEnabled)

      ScrollView {
        ForEach(1..<50) { index in
          Text("Row \(index)")
        }
      }
      .scrollEnabled(scrollEnabled)
    }
  }

Note that enabling or disabling the scroll resets the scrolling view's offset.

Next Post Previous Post