选择器与文本字段一样,需要与属性进行双向绑定,以便它们可以跟踪其值。
Picker(selection: $favoriteState, label: Text("Your name")) {
Text("Paul").tag("Paul")
Text("Chris").tag("Chris")
Text("Mark").tag("Mark")
Picker 必须加到 Form 视图里,label 标签才会显示。另外即使标签文本不可见,它仍然很有用,因为 VoiceOver 在阅读屏幕时会使用它。
// 首先,选择器可以设置 label 文字
Picker(label: Text("喜欢的课程")){ ... }
selection 参数是需要和【状态参数】双向绑定的,以此决定选择器的值是什么
//先要定义状态参数
@State private var favoriteState = 1
//将 selection 参数,双向绑定到状态参数
Picker(selection: $favoriteState){ ... }
// 选择器后面大括号的闭包,主要是设置选择器的 UI ,视图是什么样的
Picker(selection: $favoriteState, label: Text("喜欢的课程")){
Text("SwiftUI")
Text("React")
Text("SwiftUI")
}
// 选项一般用循环“数组”生成
Picker("How pay?", selection: $paymentType) {
ForEach(paymentTypes, id: \\.self) {
Text($0)
}
}
// 然后需要给闭包的每一项,后面添加 tag 修饰符
Picker(selection: $favoriteState, label: Text("喜欢的课程")){
Text("SwiftUI").tag(0)
Text("React").tag(1)
Text("SwiftUI").tag(2)
}
// tag的值可以是整数,也可以是字符串、布尔值等;它要和前面绑定的状态属性的类型一致,这样才能映射。
要获取或设置选择器的值,需要将其绑定到变量。 然后将此变量传递到选择器的初始化器中。 然后,您需要做的就是更改此绑定变量的值,以选择您想要在选择器中显示的行。 或者读取绑定变量的值,以查看当前选择的行。
// 示例:Picker 使用 tag(字符串) 来标识每一项
@State private var selectedName = "Paul"
var body: some View {
VStack {
Picker("Your name", selection: $selectedName) {
Text("Paul").tag("Paul")
Text("John").tag("John")
Text("Sarah").tag("Sarah")
}
Text("Selected name: \\(selectedName)")
}
}
例如用于切换排序规则上,选了哪个选项,就更新一个数组类型的状态属性。
@State private var sortOrder = [
SortDescriptor(\\User.name),
SortDescriptor(\\User.joinDate),
]
// 用 tag 修饰符,包裹具体选项的值(可以是任何值)。该值与状态属性绑定
Picker("Sort", selection: $sortOrder) {
Text("Sort by Name")
.tag([
SortDescriptor(\\User.name),
SortDescriptor(\\User.joinDate),
])
Text("Sort by Join Date")
.tag([
SortDescriptor(\\User.joinDate),
SortDescriptor(\\User.name)
])
}
在子视图代码里设置 tag 值,在父视图中实例化,实例化时再给他赋值。
// 父视图:实例化子视图时传入 name 参数,作为 tag 的值
Picker(selection: $youTuberName, label: Text("")) {
// 这里不要打tag,因为在子视图里打了
Row(name: "Sean")
Row(name: "Chris")
Row(name: "Mark")
}
// 子视图:加了tag,但是tag的值是未明确的,等待实例化时才能获取填入
struct Row : View {
// 接受一个参数
var name: String
var body: some View {
return HStack {
Image(systemName: "person.fill")
.padding(.trailing)
.foregroundColor(Color.red)
Text(name)
}
// 在return后打tag
.tag(name)
}
}
// 以上例子也可以通过 ForEach 循环创建
// 例如,将选项存储到数组中
var youTubers = ["Sean", "Chris", "Mark", "Scott", "Paul"]
// 第1个参数双向绑定状态参数
Picker(selection: $youTuberName, label: Text("")) {
// 从数组里进行循环
ForEach(youTubers, id: \\.self) {
// 设了个参数是name
name in
Row(name: name)
}
// 还是在抽出的子视图里加
struct Row : View {
var name: String
var body: some View {
HStack {
Image(systemName: "person.fill")
Text(name)
}
.tag(name)
}
}
如果希望不设置默认选中项,可以让状态属性的初始值不等于任何一个tag:
// 例如:让初始值等于 0
@State private var selection = 0
Picker("", selection: $selection) {
Text("One").tag(1)
Text("Two").tag(2)
Text("Three").tag(3)
}
Picker 带有许多替代样式,具体取决于您希望事物的行为方式。
菜单样式,是选择器的默认样式。其表现是直接在当前页面展开一个小浮层,显示所有选项。
// 将 .pickerStyle(.navigationLink) 修饰符添加到选择器
Picker(selection: $favoriteState, label: Text("")) { ... }
.pickerStyle(.navigationLink)
// 这时会在右边看到一个灰色箭头。但整行将显示为灰色,且点击时不会显示任何内容
// 需要做的是提供一个包裹选择器的 NavigationStack,它会做两件事:在顶部提供一些空间来放置标题,并且点击后还会导航到新视图中
NavigationStack {
Form {
Picker(selection: $favoriteState, label: Text("")) { ... }
.pickerStyle(.navigationLink)
}
}
分段式样式适用于有限选项。 为了获取或设置所选段,您需要将其绑定到变量。 此变量被传递到分段控件(Picker)的初始化器中。 Segmented 是收缩型视图。
//例如:
//1. 定义一个数组储存选项
let tipPercentages = [10, 15, 20, 25, 0]
@State private var tipPercentage = 10
//2. 双向绑定之前定义的选择的值,并通过循环读取选项构建UI
Picker("Tip percentage", selection: $tipPercentage) {
ForEach(tipPercentages, id: \\.self) {
Text($0, format: .percent)
}
}
//3. 将 .pickerStyle()修饰符添加到Picker,目前有两种写法
.pickerStyle(.segmented)
.pickerStyle(SegmentedPickerStyle())
轮子样式会在当前页面展开一个滑轮进行选择。
.pickerStyle(.wheel)