iOS Development

ios – Why is my looping scrollview leaping round?

Spread the love


I am attempting to make a horizontal scrollview that loops. All of the options I’ve discovered on-line for this downside embrace including copies of things firstly or finish of the record. The ingredient(s) inside have state and their look modifications based mostly on that state.

The issue is that when reaching the top, the subsequent (first) merchandise is caught with its preliminary state quite than the present state. This leads to jerky conduct: display screen 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 you will discover the working bare-bones instance right here: Github

struct InfiniteHorizontalScrollView2<Content material: View, Merchandise: RandomAccessCollection>: View the place Merchandise.Factor: Identifiable {
    var width: CGFloat
    var objects: Merchandise
    var repeatingCount = 1
    @ViewBuilder var content material: (Merchandise.Factor) -> Content material
    
    var physique: some View {
        ScrollView(.horizontal) {
            LazyHStack(spacing: 0) {
                ForEach(objects) { merchandise in
                    content material(merchandise)
                }
                
                ForEach(0..<repeatingCount, id: .self) { index in
                    let merchandise = Array(objects)[index % items.count]
                    content material(merchandise)
                }
            }
            .background {
                ScrollViewHelper(
                    width: width,
                    itemsCount: objects.depend
                )
            }
        }
    }
}

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.foremost.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
            }
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *