尝试在 SwiftUI 列表中使用 ScrollViewReader 滚动时发生崩溃

Gro*_*top 9 ios swiftui swiftui-list

我试图使用 ScrollViewReader 滚动到 SwiftUI 列表中新添加的视图,但在添加一些项目后,scrollTo(_:) 中的 EXC_BAD_INSTRUCTION 不断崩溃。我正在使用 Xcode 14.0.1 和 iOS 16.0 模拟器。

这是展示该问题的最小演示:

struct ContentView: View {

    @State var items = [Item]()
    @State var scrollItem: UUID? = nil
    
    var body: some View {
        NavigationView {
            ScrollViewReader { proxy in
                List {
                    ForEach(items) { item in
                        Text(item.id.uuidString)
                            .id(item.id)
                    }
                }
                .listStyle(.inset)
                .onChange(of: scrollItem) { newValue in
                    proxy.scrollTo(newValue)
                }
            }
            .navigationTitle("List Demo")
            .toolbar {
                Button("Add") {
                    addItem()
                }
            }
        }
    }

    func addItem() {
        items.append(Item())
        scrollItem = items.last?.id
    }
}

struct Item: Identifiable {
    let id = UUID()
}
Run Code Online (Sandbox Code Playgroud)

我可以使用 ScrollView 而不是列表来解决这个问题,但我想在实际项目中使用本机滑动删除功能。

wzb*_*zon 2

List中没有得到很好的支持ScrollViewReader。请参阅此线程

这个解决方案很丑陋,但是有效。不好的是,当您添加新项目时,列表会闪烁。我使用了上面线程中的想法之一。

import SwiftUI

struct ContentView: View {

    @State var items = [Item]()
    @State var scrollItem: UUID? = nil
    @State var isHidingList = false

    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {
                if isHidingList {
                    list.hidden()
                } else {
                    list
                }
            }
            .onChange(of: scrollItem) { _ in
                DispatchQueue.main.async {
                    self.isHidingList = false
                }
            }
            .navigationTitle("List Demo")
            .toolbar {
                Button("Add") {
                    addItem()
                }
            }
        }
    }

    var list: some View {
        ScrollViewReader { proxy in
            List {
                ForEach(items) { item in
                    Text(item.id.uuidString)
                        .id(item.id)
                }
            }
            .listStyle(.inset)
            .onChange(of: scrollItem) { newValue in
                guard !isHidingList else { return }
                proxy.scrollTo(newValue)
            }
            .onAppear() {
                guard !isHidingList else { return }
                proxy.scrollTo(scrollItem)
            }
        }
    }

    func addItem() {
        isHidingList = true
        items.append(Item())
        scrollItem = items.last?.id
    }

}

struct Item: Identifiable {
    let id = UUID()
}
Run Code Online (Sandbox Code Playgroud)