swiftui ScrollViewReader scrollTo 无法正常工作

swiftui ScrollViewReader scrollTo not correct working

我正在使用 swiftui 开发一个应用程序。缩放后,当我说用 ScrollViewReader 滚动到角落时,它会离开屏幕。我的代码在下面。尝试几次后失败。它不是每次都这样做。

 import SwiftUI

struct ContentView: View {
    @State var zoomIn = false
    
    var body: some View {
        GeometryReader { g in
            ScrollViewReader { reader in
                
                ScrollView([.horizontal,.vertical], showsIndicators: false) {
                    
                    VStack(spacing: 20) {
                        ForEach(0 ..< 11, id:\.self) { row in
                            HStack(spacing: 20) {
                                ForEach(0 ..< 11, id:\.self) { column in
                                    Text("Item \(row) \(column)")
                                        .foregroundColor(.white)
                                        .frame(width: zoomIn ? 70 : 35, height: zoomIn ? 70 : 35)
                                        .background(Color.red)
                                        .id("\(row)\(column)")
                                        .onTapGesture {
                                            withAnimation {
                                                reader.scrollTo( ["00", "010","100","1010"].randomElement()!)
                                            }
                                        }
                                }
                            }
                        }
                    }
                    
                    Button("Zoom") {
                        withAnimation {
                            zoomIn.toggle()
                        }
                    }
                }
            }
        }
    }
    
}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

我的主屏幕。

在 scrollTo

之后

我认为您遇到的问题是 2 ForEach 似乎无法与 ScrollReader 配合使用。我采用了不同的方法并使用了可识别的结构和 LazyVGrid。这让我可以使用一个 ForEach 并用 UUID 标识各个方块。然后我在 scrollTo() 中使用了相同的 UUID。我 运行 遇到的唯一困难是 ScrollReader 不知道如何处理双向 ScrollView,所以我创建了一个返回 UnitPoint 的函数并将其用作scrollTo() 中的锚点。这似乎已经成功了,而且工作起来非常可靠。

struct BiDirectionScrollTo: View {
    
    let scrollItems: [ScrollItem] = Array(0..<100).map( { ScrollItem(name: [=10=].description) })
    
    let columns = [
        // Using 3 grid items forces there to be 3 columns
        GridItem(.fixed(80)),
        GridItem(.fixed(80)),
        GridItem(.fixed(80)),
        GridItem(.fixed(80)),
        GridItem(.fixed(80)),
        GridItem(.fixed(80)),
        GridItem(.fixed(80)),
        GridItem(.fixed(80)),
        GridItem(.fixed(80)),
        GridItem(.fixed(80))
    ]
    
    init() {
        
    }
    var body: some View {
        ScrollViewReader { reader in
            ScrollView([.horizontal,.vertical], showsIndicators: false) {
                LazyVGrid(columns: columns, spacing: 20) {
                    ForEach(scrollItems, id: \.id) { item in
                        Text("Item \(item.name)")
                            .foregroundColor(.white)
                            .frame(width: 80, height: 80)
                            .background(Color.red)
                            .id(item.id)
                            .onTapGesture {
                                withAnimation {
                                    if let index = [0, 9, 55, 90, 99].randomElement() {
                                        print(index)
                                        reader.scrollTo(scrollItems[index].id, anchor: setUnitPoint(index))
                                    }
                                }
                            }
                    }
                }
            }
        }
    }
    private func setUnitPoint(_ index:Int) -> UnitPoint {
        switch true {
        case index % 10 < 2 && index / 10 < 2:
             return .topLeading
         case index % 10 >= 7 && index / 10 < 7:
            return .topTrailing
        case index % 10 < 2 && index / 10 >= 7:
            return .bottomLeading
        case index % 10 >= 2 && index / 10 >= 7:
            return .bottomTrailing
        default:
            return .center
        }
    }
}


struct ScrollItem: Identifiable {
    let id = UUID()
    var name: String
}