SwiftUI 问答之Picker滚轮选择器选择在滚动时跳回第一项

实战问题

我正在尝试使用 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)

解决方案

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设置为视图。


精品教程推荐


加入我们一起学习SwiftUI

QQ:3365059189
SwiftUI技术交流QQ群:518696470
教程网站:www.openswiftui.com

发表回复