How it works
AnyScrollTargetBehavior is a type-erased wrapper around any value that conforms to the ScrollTargetBehavior protocol. A scroll target behavior decides where a scroll view comes to rest once a drag or fling ends — for example, snapping to the leading edge of the nearest view rather than stopping at an arbitrary offset. Because concrete behaviors such as view-aligned and paging snapping have different underlying types, AnyScrollTargetBehavior gives you a single, uniform type to store, pass around, or return from a function when the specific behavior is chosen at runtime. Reach for it whenever you need to treat differing behaviors interchangeably while still applying them through the standard scrollTargetBehavior(_:) modifier.
Identify the snap targets with scrollTargetLayout()
A scroll target behavior can only align to candidates it knows about. Applying
scrollTargetLayout()to the container that holds the repeating content — here theHStackof colored cards inside theScrollView— marks each of its subviews as an individual scroll target that the behavior can snap to.Attach the behavior with scrollTargetBehavior(_:)
The
scrollTargetBehavior(_:)modifier on theScrollViewis where any ScrollTargetBehavior takes effect. In the example it receives.viewAligned, and SwiftUI wraps that concrete behavior in an AnyScrollTargetBehavior so the modifier can accept it uniformly alongside any other behavior.Erase a concrete behavior into AnyScrollTargetBehavior
When you hold a behavior whose exact type varies — say you compute whether to use
.viewAlignedor.pagingbased on state — you wrap it in AnyScrollTargetBehavior so every branch yields the same type. The result still flows intoscrollTargetBehavior(_:)exactly like the.viewAlignedvalue does in the example.Conform to ScrollTargetBehavior
AnyScrollTargetBehavior conforms to the same ScrollTargetBehavior protocol it wraps, forwarding the resting-position calculation to the value inside it. That conformance is what lets the erased value drive the snapping of the cards laid out by
scrollTargetLayout()without the call site needing to know which concrete behavior is in use.
.scrollTargetBehavior(.viewAligned) to .scrollTargetBehavior(.paging) and watch the scroll view snap a full page at a time instead of aligning to each card.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct AnyScrollTargetBehaviorDemo: View {
let colors: [(String, Color)] = [("Red", .red), ("Green", .green), ("Blue", .blue), ("Orange", .orange)]
var body: some View {
ScrollView(.horizontal) {
HStack(spacing: 16) {
ForEach(colors, id: \.0) { name, color in
RoundedRectangle(cornerRadius: 16)
.fill(color)
.frame(width: 200, height: 160)
.overlay(Text(name).font(.title2).bold().foregroundStyle(.white))
}
}
.scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)
.padding()
}
}