Skip to content

ScrollView Scroll Phases (SwiftUI)

A SwiftUI guide for coding agents. Also covers onscrollphasechange, detect scrolling state, is scroll view scrolling, scroll deceleration event, scroll velocity context.

The onScrollPhaseChange view modifier reports what state a ScrollView is in: idle, touched, dragged, decelerating, or animating. Use it to react to scrolling itself, such as pausing expensive work while content is in motion.

The Phases

ScrollPhase is a frozen enum with five cases:

  • idle: nothing is happening.
  • tracking: the user touches the content but has not dragged yet.
  • interacting: the user drags to start or continue scrolling.
  • decelerating: the finger lifted and the view coasts to its destination.
  • animating: code scrolls the view, through ScrollPosition or ScrollViewReader.

Observing Changes

The action closure receives the old and new phase on every transition.

ScrollView {
  ForEach(1..<100, id: \.self) { item in
    Text(verbatim: item.formatted())
  }
}
.onScrollPhaseChange { oldPhase, newPhase in
  guard oldPhase != newPhase else { return }
  print(newPhase)
}

A second overload adds a ScrollPhaseChangeContext, which carries the scroll velocity and the current ScrollGeometry.

.onScrollPhaseChange { oldPhase, newPhase, context in
  print(context.geometry.visibleRect)
}

The Common Case: isScrolling

Most callers only need "moving or not". ScrollPhase.isScrolling is true for every phase except idle. Here it redacts rows while the view scrolls.

@State private var isScrolling = false

ScrollView {
  ForEach(1..<100, id: \.self) { item in
    Text(verbatim: item.formatted())
  }
  .redacted(reason: isScrolling ? .placeholder : [])
}
.onScrollPhaseChange { oldPhase, newPhase in
  isScrolling = newPhase.isScrolling
}

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-mastering-scrollview-scroll-phases" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems