SwiftUI : Picker does not update correctly when changing datasource

前端 未结 4 1152
花落未央
花落未央 2020-12-30 11:40

I have just started learning SwiftUI and got stuck somewhere!

I am trying to change segment styled picker datasource when changing value of another segment. But some

4条回答
  •  孤城傲影
    2020-12-30 12:39

    FYI above answers do not work for the Wheelpickerstyle in SwiftUI. The count of units will stay at the initial value, so if you start with Temperature and then switch to Length, you will be missing the last two values of Length array. If you go the other way, your app will crash with an out of bounds.

    It took me forever to work out a solution. It seems it is a bug in the Wheelpickerstyle. The workaround is to update the ID of the picker, which prompts it to reload all data sources. I've included an example below.

    import SwiftUI  
    
    // Data  
    struct Item: Identifiable {  
        var id = UUID()  
        var category:String  
        var item:String  
    }  
    let myCategories:[String] = ["Category 1","Category 2"]  
    let myItems:[Item] = [  
        Item(category: "Category 1", item: "Item 1.1"),  
        Item(category: "Category 1", item: "Item 1.2"),  
        Item(category: "Category 2", item: "Item 2.1"),  
        Item(category: "Category 2", item: "Item 2.2"),  
        Item(category: "Category 2", item: "Item 2.3"),  
        Item(category: "Category 2", item: "Item 2.4"),  
    ]  
    
    // Factory  
    class MyObject: ObservableObject {  
        // Category picker variables  
        @Published var selectedCategory:String = myCategories[0]  
        @Published var selectedCategoryItems:[Item] = []  
        @Published var selectedCategoryInt:Int = 0 {  
            didSet {  
                selectCategoryActions(selectedCategoryInt)  
            }  
        }  
        // Item picker variables  
        @Published var selectedItem:Item = myItems[0]  
        @Published var selectedItemInt:Int = 0 {  
            didSet {  
                selectedItem = selectedCategoryItems[selectedItemInt]  
            }  
        }  
        @Published var pickerId:Int = 0  
        // Initial category selection  
        init() {  
            selectCategoryActions(selectedCategoryInt)  
        }  
        // Actions when selecting a new category  
        func selectCategoryActions(_ selectedCategoryInt:Int) {  
            selectedCategory = myCategories[selectedCategoryInt]  
            // Get items in category  
            selectedCategoryItems = myItems.filter{ $0.category.contains(selectedCategory)}  
            // Select initial item in category  
            let selectedItemIntWrapped:Int? = myItems.firstIndex { $0.category == selectedCategory }  
            if let selectedItemInt = selectedItemIntWrapped {  
                self.selectedItem = myItems[selectedItemInt]  
            }  
            self.pickerId += 1 // Hack to change ID of picker. ID is updated to force refresh  
        }  
    }  
    
    // View  
    struct ContentView: View {  
        @ObservedObject var myObject = MyObject()  
    
        var body: some View {  
                VStack(spacing: 10) {  
                    Section(header: Text("Observable Object")) {  
                        Text("Selected category: \(myObject.selectedCategory)")  
                        Text("Items in category: \(myObject.selectedCategoryItems.count)")  
                        Text("PickerId updated to force refresh  \(myObject.pickerId)")  
                        Text("Selected item: \(myObject.selectedItem.item)")  
                        Picker(selection: self.$myObject.selectedCategoryInt, label: Text("Select category")) {  
                            ForEach(0 ..< myCategories.count, id: \.self) {  
                                Text("\(myCategories[$0])")  
                            }  
                        }.labelsHidden()  
    
                        Picker(selection: self.$myObject.selectedItemInt, label: Text("Select object item")) {  
                            ForEach(0 ..< self.myObject.selectedCategoryItems.count, id: \.self) {  
                                Text("\(self.myObject.selectedCategoryItems[$0].item)")  
                            }  
                        }  
                        .labelsHidden()  
                        .id(myObject.pickerId) // Hack to get picker to reload data. ID is updated to force refresh.  
                    }  
                    Spacer()  
                }  
        }  
    }  
    
    struct ContentView_Previews: PreviewProvider {  
        static var previews: some View {  
            ContentView()  
        }  
    }  
    

提交回复
热议问题