Hey everyone, hstack-snap-to-scroll
is a tiny Swift package that gives your HStack snapping capabilities with just one line of code.
A similarly tiny gif showing the package at work:
A code example:
import SnapToScroll // Step 1
...
HStackSnap(alignment: .center(32)) { // Step 2
ForEach(myModels) { viewModel in
MyView(
selectedIndex: $selectedIndex,
viewModel: viewModel
)
.snapAlignmentHelper(id: viewModel.id) // Step 3
}
}
For more examples, visit the GitHub repo and view the demo project.
Configuration
HStackSnap
comes with two customizable properties:
-
alignment
: The way you'd like your elements to be arranged.-
leading(CGFloat)
: Aligns your child views to the leading edge ofHStackSnap
. This configuration supports elements of various sizes, so long as they don't take up all available horizontal space (which would extend beyond the screen). Use the value to set the size of the left offset. -
center(CGFloat)
: Automatically aligns your child view to the center of the screen, using the offset value you've provided. This is accomplished with inside of the.snapAlignmentHelper
which sets the frame width based on the available space. Note that setting your own width elsewhere may produce unexpected layouts.
-
-
coordinateSpace
: Option to set custom name for the coordinate space, in the case you're using multipleHStackSnap
s of various sizes. If you use this, set the same value in.snapAlignmentHelper
.
.snapAlignmentHelper
comes with two options as well:
-
id
: Required. A unique ID for the element. -
coordinateSpace
: Same as above.
One neat thing not shown in the example above but is covered in the project's demo is a way to receive the latest "snap event" through a closure. This way, you can make use of this information elsewhere, or modify the appearance of the currently selected item.
How it Works
At render, HStackSnap
reads the frame data of each child element and calculates the scrollOffset
each element should use. Then, on DragGesture.onEnded
, the nearest snap location is calculated, and the scroll offset is set to this point.
I'm Open to Feedback!
If you found this interesting or have questions / feedback, I'd love to hear your thoughts.