【问题标题】:swiftui ScrollViewReader scrollTo not correct workingswiftui ScrollViewReader scrollTo 不正确工作
【发布时间】:2021-11-30 20:19:10
【问题描述】:

我正在使用 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()
    }
}

我的主屏幕。

滚动到之后

【问题讨论】:

    标签: swiftui swiftui-scrollview scrollviewreader


    【解决方案1】:

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

    struct BiDirectionScrollTo: View {
        
        let scrollItems: [ScrollItem] = Array(0..<100).map( { ScrollItem(name: $0.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
    }
    

    【讨论】:

    • 很好。弯道没问题。但这一次它去到了内部错误的地方。例如滚动索引是 50,但它变成了 70。我不明白你为什么这样做?我只是将帧更改为 300 并让 index = Array(0..
    • 这是基于您的问题的示例。如果您想在中心放置一些东西,只需在“setUnitPoint”函数中为它添加一个案例。你可以看到它是如何完成的。这就是为什么我将default 设置为.center 来处理中间情况,但我并没有真正在switch 中为它们编码。我只是将视图划分为四个象限,但如果你将它们更靠近边缘,.default 将占据中间位置。
    • 我将它们全部更改为居中。滚动到不相关的地方。代码没有问题,为什么会这样?我在 ios 15 iphone 13 模拟器和 ipad pro 12.9 ios 15 模拟器上试过。结果相同
    • 我更新了我的答案,向您展示如何使其居中。我认为问题是,如果您将所有func setUnitPoint 更改为.center,您就是在告诉它尝试将角落放在中心,这是行不通的。相反,您需要确定您的方格之一是在中心还是在角落,然后去那里。如果您查看更新后的func setUnitPoint(),您会看到我更改了测试角的原因。您还可以添加类似的测试以使其发挥作用。我没有完成所有的情况。您需要自己决定要承保哪些案件。
    • 我在转换行和列时犯了一个错误:(它现在工作得很好。非常感谢@Yrb
    猜你喜欢
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 2015-07-04
    • 1970-01-01
    相关资源
    最近更新 更多