I need to create an infinite horizontal scrolling with ScrollView
to scroll a panorama image. So I would like to make this scrolling infinite from both sides, is there any possible way to make it? I have searched maybe using ScrollViewReader
can achieve this but no luck.
ScrollView(.horizontal, showsIndicators: false) {
Image("panorama")
.resizable()
.scaledToFill()
}
Actually for such prepared image it is enough to load it only once, and we need only to Image presenters for it (note: they do not copy memory, but use the same loaded image). Everything else is just about layout on the fly moving current of-screen item depending on drag direction to left or to the right of current one.
Tested with Xcode 13.4 / iOS 15.5
Main part of code:
struct PanoramaView: View {
let image: UIImage
private struct Item: Identifiable, Equatable {
let id = UUID()
var pos: CGFloat!
}
@State private var items = [Item(), Item()]
// ...
var body: some View {
GeometryReader { gp in
let centerY = gp.size.height / 2
ForEach($items) { $item in
Image(uiImage: image)
.resizable().aspectRatio(contentMode: .fill)
.position(x: item.pos ?? 0, y: centerY)
.offset(x: dragOffset)
}
}
.background(GeometryReader {
Color.clear.preference(key: ViewSizeKey.self,
value: $0.frame(in: .local).size)
})
.onPreferenceChange(ViewSizeKey.self) {
setupLayout($0)
}
.contentShape(Rectangle())
.gesture(scrollGesture)
}
and usage
let panorama = UIImage(contentsOfFile: Bundle.main.path(forResource: "panorama", ofType: "jpeg")!)!
var body: some View {
PanoramaView(image: panorama)
.frame(height: 300) // to demo of dynamic internal layout
}