Skip to content

Instantly share code, notes, and snippets.

@dkasaj
Created December 21, 2024 11:10
Show Gist options
  • Save dkasaj/77b7c68e0b5d01d814382c03a824a6d1 to your computer and use it in GitHub Desktop.
Save dkasaj/77b7c68e0b5d01d814382c03a824a6d1 to your computer and use it in GitHub Desktop.
SwiftUI ScrollView Centered Items with ScrollTargetBehavior
import SwiftUI
struct ContentView: View {
private let colors: [Color] = [.red, .orange, .yellow, .green, .blue, .indigo, .purple]
private let itemDimension = UIScreen.main.bounds.width * 0.7
private let itemSpacing = CGFloat(16)
private let scrollViewHorizontalInset = CGFloat(16)
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack(spacing: itemSpacing) {
ForEach(colors, id: \.self) { color in
VStack {
Rectangle()
.foregroundStyle(color)
.frame(width: itemDimension, height: itemDimension * 2/3)
Text(color.description.capitalized)
}
}
}
.padding(.horizontal, scrollViewHorizontalInset)
}
.scrollTargetBehavior(CenteredBehavior(itemWidth: itemDimension,
itemSpacing: itemSpacing,
scrollViewHorizontalInset: scrollViewHorizontalInset))
}
}
#Preview {
ContentView()
}
struct CenteredBehavior: ScrollTargetBehavior {
private let itemWidth: CGFloat
private let itemSpacing: CGFloat
private let scrollViewHorizontalInset: CGFloat
private let widthOfItemWithSpacing: CGFloat
init(itemWidth: CGFloat, itemSpacing: CGFloat, scrollViewHorizontalInset: CGFloat) {
self.itemWidth = itemWidth
self.itemSpacing = itemSpacing
self.scrollViewHorizontalInset = scrollViewHorizontalInset
widthOfItemWithSpacing = itemWidth + itemSpacing
}
func updateTarget(_ target: inout ScrollTarget, context: TargetContext) {
let itemIndex = round((target.rect.origin.x - scrollViewHorizontalInset) / widthOfItemWithSpacing)
let itemMinX = itemIndex * widthOfItemWithSpacing
let amountToShiftLeft = (context.containerSize.width - itemWidth) / 2
let newMinX = scrollViewHorizontalInset + itemMinX - amountToShiftLeft
target.rect.origin.x = newMinX
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment