I am attempting to make a horizontal scrollview that loops. All of the options I’ve discovered on-line for this drawback embody including copies of things at the start or finish of the record. The ingredient(s) inside have state and their look adjustments primarily based on that state.
The issue is that when reaching the tip, the following (first) merchandise is caught with its preliminary state slightly than the present state. This leads to jerky conduct: display recording
I’ve tried this with each instance I’ve discovered on-line with very related outcomes every time. The instance within the video is made with the next code, though yow will discover the bare-bones instance right here: Github
struct InfiniteHorizontalScrollView2<Content material: View, Merchandise: RandomAccessCollection>: View the place Merchandise.Ingredient: Identifiable {
var width: CGFloat
var gadgets: Merchandise
var repeatingCount = 1
@ViewBuilder var content material: (Merchandise.Ingredient) -> Content material
var physique: some View {
ScrollView(.horizontal) {
LazyHStack(spacing: 0) {
ForEach(gadgets) { merchandise in
content material(merchandise)
}
ForEach(0..<repeatingCount, id: .self) { index in
let merchandise = Array(gadgets)[index % items.count]
content material(merchandise)
}
}
.background {
ScrollViewHelper(
width: width,
itemsCount: gadgets.rely
)
}
}
}
}
struct ScrollViewHelper: UIViewRepresentable {
var width: CGFloat
var itemsCount: Int
func makeCoordinator() -> Coordinator {
return Coordinator(
width: width,
itemsCount: itemsCount
)
}
func makeUIView(context: Context) -> some UIView {
return .init()
}
func updateUIView(_ uiView: UIViewType, context: Context) {
DispatchQueue.most important.asyncAfter(deadline: .now() + 0.06) {
if let scrollView = uiView.superview?.superview?.superview as? UIScrollView, !context.coordinator.isAdded {
scrollView.delegate = context.coordinator
context.coordinator.isAdded = true
}
}
}
class Coordinator: NSObject, UIScrollViewDelegate {
var width: CGFloat
var itemsCount: Int
init(
width: CGFloat,
itemsCount: Int
) {
self.width = width
self.itemsCount = itemsCount
}
var isAdded: Bool = false
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let minX = scrollView.contentOffset.x
let mainContentSize = CGFloat(itemsCount) * width
if minX > mainContentSize {
scrollView.contentOffset.x -= mainContentSize
}
if minX < 0 {
scrollView.contentOffset.x += mainContentSize
}
}
}
}