Reading time: 1 min

This recipe is about how to scroll a SwiftUI ScrollView programatically. Here's a quick breakdown of what to do:

  • For iOS 13 - tough luck - it can't be done. For whatever reason, this is one of things that were deemed less important for the initial release of SwiftUI.
  • For iOS 14 and above - embed your ScrollView's root view in a ScrollViewReader, and then use the scrollTo method.

scrollTo takes as a parameter the ID of the child view to scroll to. It's not a position or a Y value - you can't scroll to whichever point in the ScrollView you'd like. Set the ID of the child view using the method id, that's available for all SwiftUI Views:

let range = 1..<30
var body: some View {
  ScrollView {
    ScrollViewReader { proxy in
      ForEach(1..<30) { value in
        Text("\(value)")
          .id(value) // the ID can be any hashable
      }
      Button("Scroll to random") {
        proxy.scrollTo(Int.random(in: range))
       }
    }
  }
}

If your app needs to support iOS 13 as well, use pack the scrolling action in an optional closure, and use the #available conditional:

let range = 1..<30
var body: some View {
  ScrollView {
    if #available(iOS 14.0, *) {
      ScrollViewReader { proxy in
        mainView {
          proxy.scrollTo(Int.random(in: range))
        }
      }
    } else {
      mainView()
    }
 }
}

func mainView(scroll: (() -> Void)? = nil) -> some View {
  Group {
    ForEach(1..<30) { value in
      Text("\(value)")
        .id(value) // the ID can be any hashable
    }
    Button((scroll != nil) ? "Scroll to random" : "I'm kinda useless :(") {
      scroll?()
    }
  }
}

Next Post Previous Post