【问题标题】:SwiftUI wheel picker selection skips back to first item when scrolling滚动时,SwiftUI 滚轮选择器选择跳回第一项
【发布时间】:2022-01-20 00:00:18
【问题描述】:

我可能已经确定了整个互联网的范围,但找不到答案,因此我伸出了手。

我正在尝试使用 SwiftUI 滚轮选择器让用户进行语言选择,但选择器会粘在列表中的第一个项目上,并且在尝试滚动浏览时不会滚动到新的选择。这在模拟器和物理设备上都会发生。

我花了一天时间阅读各种博客、论坛、问题、教程……所有这些。从我的代码中可以看出,看起来一切都井井有条,但显然我遗漏了一些东西!

有人可以帮我诊断一下吗?代码和环境详情如下。

我认为的轮子选择器:

Picker("", selection: $model.selectedLanguageIndex, content: {
    ForEach(0..<model.languages.count, id: \.self) { index in
        Text(model.languages[index].name).tag(index)
    }
}).pickerStyle(.wheel)

视图声明了一个视图模型:

@StateObject private var model = MyView.viewModel()

并且视图在父元素外标签处也有onAppear函数:

.onAppear(perform: model.load)

视图模型如下所示:

extension MyView {
    class viewModel: ObservableObject {
        @Published var languages = [language]()
        @Published var selectedLanguageIndex = 0
        
        func load() {
            MyService.getLanguages { (success, error, languages) in
                guard success, error == nil, let languages = languages, !languages.isEmpty else { return }
                DispatchQueue.main.async { self.languages = languages }
            }
        }
    }
}

language 模型与 languages 集合一起使用:

struct language: Hashable, Identifiable {
    let id: String
    let code: String
    let name: String
}

环境:

Xcode 13.2
Mac Mini M1 2020 macOS Monterey (Dev machine)
iPhone 11 Pro Max iOS 15.1 (Physical device used for testing)

任何帮助将不胜感激!

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    我无法复制您的问题。使用以下测试代码对我来说一切都很好。 在 Mac Monterey 上,Xcode 13.2,目标 ios 15 和催化剂 12。

    此测试代码对您有用吗?如果是这样,您的问题可能出在您未显示的其他代码中。

    这是我的测试代码:

    import SwiftUI
    
    @main
    struct TestApp: App {
        var body: some Scene {
            WindowGroup {
                ContentView()
            }
        }
    }
    
    struct ContentView: View {
        @StateObject private var model = ContentView.viewModel()
    
        var body: some View {
            Picker("", selection: $model.selectedLanguageIndex, content: {
                ForEach(0..<model.languages.count, id: \.self) { index in
                    Text(model.languages[index].name).tag(index)
                }
            }).pickerStyle(.wheel)
                .onAppear {
                    model.load()
                }
        }
    }
    
    extension ContentView {
        class viewModel: ObservableObject {
            @Published var languages = [Language]()
            @Published var selectedLanguageIndex = 0
            
            func load() {
    //            MyService.getLanguages { (success, error, languages) in
    //                guard success, error == nil, let languages = languages, !languages.isEmpty else { return }
    //                DispatchQueue.main.async { self.languages = languages }
    //            }
                // for testing
                languages = [Language(id: "1", code: "1", name: "name 1"),
                             Language(id: "2", code: "2", name: "name 2"),
                             Language(id: "3", code: "3", name: "name 3"),
                             Language(id: "4", code: "4", name: "name 4")]
            }
        }
    }
    
    struct Language: Hashable, Identifiable {
        let id: String
        let code: String
        let name: String
    }
    

    注意:我个人会将viewModel 放在extension 之外的视图中。

    【讨论】:

    • 感谢@workingdog 的回答,看起来在同一个线程上实例化集合似乎很奇怪(而不是DispatchQueue.main.async)。不是我的理想方案,但我一定会使用它!
    • 在我的测试中,更新包含在DispatchQueue.main.async {...} 中的languages 数组也很有效。我怀疑还有其他原因导致您的问题。
    猜你喜欢
    • 2014-02-15
    • 2019-01-09
    • 2019-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-28
    相关资源
    最近更新 更多