我需要使用
ScrollView
创建无限水平滚动来滚动全景图像。所以我想从两侧无限滚动,有什么办法可以做到吗?我已经搜索过也许使用ScrollViewReader
可以实现这个但没有运气。
ScrollView(.horizontal, showsIndicators: false) {
Image("panorama")
.resizable()
.scaledToFill()
}
实际上对于这样准备好的图像,只加载一次就足够了,我们只需要为它提供图像展示器(注意:他们不复制内存,而是使用相同的加载图像)。其他一切都只是关于动态移动当前屏幕项目的布局,具体取决于向左或向右拖动当前项目的方向。
使用 Xcode 13.4 / iOS 15.5 测试
代码主要部分:
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)
}
和用法
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
}
您可以将 3 张相同的全景图像并排放置(以便能够在边缘上滚动)并添加自定义 DragGesture,这基本上会跳回中间图像的相对位置。
这张图片是一个不好的例子,显然它会在真实的 360° 图像上工作得更好;)
编辑:
现在有预测的结束位置+动画和 5 张图片。
struct ContentView: View {
@State private var dragOffset = CGFloat.zero
@State private var offset = CGFloat.zero
let imageWidth: CGFloat = 500
var body: some View {
HStack(spacing: 0) {
ForEach(0..<5) { _ in
Image("image")
.resizable()
.frame(width: imageWidth)
}
}
.offset(x: offset + dragOffset)
.gesture(
DragGesture()
.onChanged({ value in
dragOffset = value.translation.width
})
.onEnded({ value in
withAnimation(.easeOut) {
dragOffset = value.predictedEndTranslation.width
}
offset = (offset + dragOffset).remainder(dividingBy: imageWidth)
dragOffset = 0
})
)
}
}