I want to create a custom scroll that snaps views to middle But I can't figure out how to set the offset correctly.
This is the sample of the scroll:
struct contentView: View {
@State var startOffset: CGFloat = 0
@State var translationWidth: CGFloat = 0
@State var offset: CGFloat = 0
@State var index: Int = 0
var body: some View {
GeometryReader { geo in
HStack {
ForEach(0..<5, id: \.self) { num in
Button(action: {
// some action
}) {
Circle()
}
.frame(width: geo.size.width)
.offset(x: -self.offset*CGFloat(self.index) + self.translationWidth)
}
}.frame(width: geo.size.width, height: 200)
.offset(x: self.startOffset )
.highPriorityGesture (
DragGesture(minimumDistance: 0.1, coordinateSpace: .global)
.onChanged({ (value) in
self.translationWidth = value.translation.width
})
.onEnded({ (value) in
if self.translationWidth > 40 {
self.index -= 1
} else if self.translationWidth < -40 {
self.index += 1
}
self.translationWidth = 0
})
)
.onAppear {
withAnimation(.none) {
let itemsWidth: CGFloat = CGFloat(geo.size.width*5) - (geo.size.width)
self.offset = geo.size.width
self.startOffset = itemsWidth/2
}
}
}
}
}
It works but it is slightly off the middle, it doesn't scroll exactly in the middle and I don't understand why.
The problem occurs with the onAppear closure:
.onAppear {
withAnimation(.none) {
let itemsWidth: CGFloat = CGFloat(geo.size.width*5) - (geo.size.width)
self.offset = geo.size.width
self.startOffset = itemsWidth/2
}
}
I might be missing some small pixels in my calculations.
UPDATE
So Apparently the HStack has a default value for spacing between views. so to fix it you should remove it like so:
HStack(spacing: 0) {
....
}