ios SwiftUI:无限滚动水平滚动视图

a6b3iqyw  于 2023-05-19  发布在  iOS
关注(0)|答案(2)|浏览(203)

我需要用ScrollView创建一个无限水平滚动来滚动全景图像。所以我想让这个滚动从两边无限,有什么可能的方法吗?我已经搜索了也许使用ScrollViewReader可以实现这一点,但没有运气。

ScrollView(.horizontal, showsIndicators: false) {
    Image("panorama")
        .resizable()
        .scaledToFill()
}
ubof19bj

ubof19bj1#

实际上,对于这样准备的图像,只需加载一次就足够了,我们只需要为它提供图像演示者(注意:它们不复制存储器,而是使用相同的加载图像)。其他的一切都只是关于布局的飞行移动当前的屏幕项目取决于拖动方向的左边或右边的当前之一。
已测试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
    }

Complete test code is here

kr98yfug

kr98yfug2#

您可以将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
                })
        )
    }
}

相关问题