【问题标题】:swift picker not selecting item快速选择器不选择项目
【发布时间】:2021-12-27 23:53:55
【问题描述】:

我想在分段选择器中显示一小部分项目。我正在传递所选项目(默认情况下为 0)。选择器显示,但未选择任何项目,并且选择器对点击无响应(在模拟器中)。我有一个非常相似的选择器,它使用百分比值,并且可以正常工作。我猜这个问题与我传递给 ForEach 循环的闭包有关,但我不清楚我应该使用什么语法,如果这确实是问题。

代码如下:

@State private var originalUnit = 0
let sourceUnits = ["meters","kilometers","feet","yards","miles"]

var body: some View {
   NavigationView {
      Form {
         Section {
             Picker("Unit", selection $originalUnit) {
                 ForEach(sourceUnits, id: \.self {
                     Text($0)
                 }
             } .pickerStyle(.segmented)
         } header: {
             Text("Choose Unit")
         }
      }  .navigationTitle("MyApp")
    }
  }
}

struct ContentView_Previews: PreviewProvider {
   static var previews: some View {
      ContentView()
    }
}

对此的任何见解将不胜感激。提前致谢!

【问题讨论】:

    标签: swift swiftui uisegmentedcontrol picker


    【解决方案1】:

    您的originalUnit (Int) 和sourceUnits (String) 之间存在类型不匹配。您的选择需要与类型匹配。

    struct ContentView: View {
        @State private var originalUnit = "meters" //<-- Here
        let sourceUnits = ["meters","kilometers","feet","yards","miles"]
        
        var body: some View {
            NavigationView {
                Form {
                    Section {
                        Picker("Unit", selection: $originalUnit) {
                            ForEach(sourceUnits, id: \.self) {
                                Text($0)
                            }
                        } .pickerStyle(.segmented)
                    } header: {
                        Text("Choose Unit")
                    }
                }  .navigationTitle("MyApp")
            }
        }
    }
    

    如果出于某种原因,您确实需要 originalUnit 成为 Int,则可以使用 enumerated(通常不是 ForEach 中大型集合的最有效方法,但这无关紧要对于这么小的东西),以便id 是索引并匹配originalUnit 的类型(Int):

    struct ContentView: View {
        @State private var originalUnit = 0
        let sourceUnits = ["meters","kilometers","feet","yards","miles"]
        
        var body: some View {
            NavigationView {
                Form {
                    Section {
                        Picker("Unit", selection: $originalUnit) {
                            ForEach(Array(sourceUnits.enumerated()), id: \.0) { //<-- .0 is the index (Int)
                                Text($0.1) //<-- .1 is the original item String
                            }
                        } .pickerStyle(.segmented)
                    } header: {
                        Text("Choose Unit")
                    }
                }  .navigationTitle("MyApp")
            }
        }
    }
    

    【讨论】:

    • 呃。谢谢你抓住这个。我错误地认为 Picker 返回了所选项目的索引。非常感谢您的回答。
    • 太好了——您可以使用绿色复选标记接受答案。如果有帮助,您也可以使用向上箭头进行投票。
    【解决方案2】:

    您可以为您的选择器行设置tag。标签是任何hashable 类型。 请参考此代码使用任何类型的对象进行选择

    struct TestView: View {
        @StateObject var viewModel = TestViewModel()
        var body: some View {
            VStack {
                Text(viewModel.selectedItem.title)
                Picker("Select item", selection: $viewModel.selectedItem) {
                    ForEach(viewModel.items) { makeRowForItem($0) }
                }
            }
        }
        
        @ViewBuilder
        func makeRowForItem(_ item: Item) -> some View {
            Text(item.title).tag(item)
        }
    }
    
    struct Item: Identifiable, Hashable {
        var id = UUID().uuidString
        var title = "Untitled"
        
        func hash(into hasher: inout Hasher) {
            hasher.combine(id)
        }
    }
    
    class TestViewModel: ObservableObject {
        @Published var selectedItem: Item
        @Published var items: [Item]
        
        init() {
            let list = (1..<10).map { Item(title: "Untitled \($0)") }
            items = list
            selectedItem = list.first!
        }
    }
    

    【讨论】:

    • 感谢您对此的解释。我会记住这一点,以备将来参考。我绝对不知道这个选项!
    猜你喜欢
    • 2019-11-24
    • 2012-06-07
    • 1970-01-01
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多