SwiftUI Picker

用于从一组互斥值中进行选择的控件
iOS 13.0+iPadOS 13.0+macOS 10.15+Mac Catalyst 13.0+tvOS 13.0+watchOS 6.0+

您可以通过提供选择绑定、标签和选择器要显示的内容来创建选择器。 将 selection 参数设置为提供要显示为当前选择的值的绑定属性。 将标签设置为一个视图,可以直观地描述在选取器中选择内容的目的,然后提供内容供选取器显示。

例如,考虑冰淇淋口味的枚举和保存所选口味的状态变量:

enum Flavor: String, CaseIterable, Identifiable {
    case chocolate, vanilla, strawberry
    var id: Self { self }
}

@State private var selectedFlavor: Flavor = .chocolate

您可以通过提供标签、与当前选择的绑定以及选择器内容的视图集合来创建选择器以在值中进行选择。 使用 tag(_:) 视图修饰符为这些内容视图中的每一个附加一个标签,以便每个选择的类型与绑定状态变量的类型相匹配:

List {
    Picker("Flavor", selection: $selectedFlavor) {
        Text("Chocolate").tag(Flavor.chocolate)
        Text("Vanilla").tag(Flavor.vanilla)
        Text("Strawberry").tag(Flavor.strawberry)
    }
}

如果您为选择器提供一个字符串标签,如上面的示例所做的那样,选择器将使用它来将 Text 视图初始化为标签。 或者,您可以使用 init(selection:content:label:) 初始化程序从其他视图组成标签。 选择器的确切外观取决于上下文。 如果您在 iOS 的列表中使用选择器,它会显示在一行中,带有标签和选定的值,以及一个 V 形表示您可以点击该行来选择一个新值:

左侧有字符串 Flavor 的列表行的屏幕截图

选项

要在不明确列出每个选项的情况下为 Picker 提供选择值,您可以使用 ForEach 创建选择器:

Picker("Flavor", selection: $selectedFlavor) {
    ForEach(Flavor.allCases) { flavor in
        Text(flavor.rawValue.capitalized)
    }
}

ForEach 使用每个选项的 id 自动为选择视图分配一个标签。 这是可能的,因为 Flavor 符合 Identifiable 协议。

上面的示例依赖于 Flavor 定义其 id 参数的类型以完全匹配选择类型的事实。 如果不是这种情况,您需要覆盖标签。 例如,考虑每种口味的 Topping 类型和建议的 Topping:

enum Topping: String, CaseIterable, Identifiable {
    case nuts, cookies, blueberries
    var id: Self { self }
}

extension Flavor {
    var suggestedTopping: Topping {
        switch self {
        case .chocolate: return .nuts
        case .vanilla: return .cookies
        case .strawberry: return .blueberries
        }
    }
}

@State private var suggestedTopping: Topping = .nuts

以下示例显示了一个绑定到 Topping 类型的选择器,而选项都是 Flavor 实例。 每个选项都使用标签修饰符将建议的浇头与其显示的风味相关联:

List {
    Picker("Flavor", selection: $suggestedTopping) {
        ForEach(Flavor.allCases) { flavor in
            Text(flavor.rawValue.capitalized)
                .tag(flavor.suggestedTopping)
        }
    }
    HStack {
        Text("Suggested Topping")
        Spacer()
        Text(suggestedTopping.rawValue.capitalized)
            .foregroundStyle(.secondary)
    }
}

当用户选择巧克力时,选择器将建议的顶部设置为关联标签中的值:

两个列表行的屏幕截图。 第一个在左边有字符串 Flavor

选择器的 ForEach 中的视图何时需要显式标记修饰符的其他示例包括:

  • 通过使用除 Self 之外的任何内容作为 id 参数类型来选择符合 Identifiable 协议的枚举案例。 例如,字符串枚举可能使用案例的 rawValue 字符串作为 id。 该标识符类型与选择类型不匹配,选择类型是枚举本身的类型。
  • 为选择输入参数使用可选值。 为此,您需要将标签修饰符的输入显式转换为 Optional 以匹配。 有关这方面的示例,请参见 tag(_:)

样式

您可以使用符合 PickerStyle 协议的样式(如分段或菜单)自定义选择器的外观和交互。 要为视图中的所有选取器实例设置特定样式,请使用 pickerStyle(_:) 修饰符。 以下示例将分段样式应用于独立选择风味和浇头的两个选择器:

VStack {
    Picker("Flavor", selection: $selectedFlavor) {
        ForEach(Flavor.allCases) { flavor in
            Text(flavor.rawValue.capitalized)
        }
    }
    Picker("Topping", selection: $selectedTopping) {
        ForEach(Topping.allCases) { topping in
            Text(topping.rawValue.capitalized)
        }
    }
}
.pickerStyle(.segmented)
两个分段控件的屏幕截图,第一个有标记段