在列表中切换选择 - SwiftUI
Toggle selection in a list - SwiftUI
希望能把我的问题解释清楚
我想 select 通过切换列表中的一些课程,但无论我尝试过什么都没有用。
我该怎么办?
感谢您的宝贵时间。
最好的,
穆拉特
struct SubjectCardsView: View {
// MARK: - Properties
@State var courses: [Course] = Bundle.main.decode("courses.json")
@State private var toggle: Bool = false
// MARK: - Body
var body: some View {
NavigationView {
List {
ForEach(courses) { course in
Section(header: Text(course.title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(course.courseName, id: \.name) { item in
Toggle(isOn: $toggle, label: {
Text(item.name)
})
}
}
}
}
.listStyle(InsetGroupedListStyle())
.navigationBarTitle("Choose your subject", displayMode: .inline).font(.system(size: 16, weight: .medium, design: .rounded))
.navigationBarItems(leading: Button(action: {
}, label: {
Text("Cancel")
}), trailing: Button(action: {
}, label: {
Text("Save")
}))
} // NavigationView
}
}
课程部分!
import Foundation
import SwiftUI
struct Course: Codable, Identifiable {
var id: Int
var title: String
var subjectCount: String
var courseName: [Content]
var isToggled = false
private var imageName: String
var image: Image {
Image(imageName)
}
enum LessonSegment: String, CaseIterable, Identifiable {
case overview
case resources
var id: String { self.rawValue }
}
enum CodingKeys: String, CodingKey {
case id
case title
case subjectCount
case imageName
case courseName
}
}
struct Content: Codable {
var id: Int
var name: String
var content: String
var assessment: String
var notify: String
}
你的 @State private var toggle: Bool = false
没有意义。你有很多课程,而不是一门课程。每门课程都应该有自己的开关 on/off,这是你开始做的:
struct Course: Codable, Identifiable {
var isToggled = false /// here!
...
}
要使用它,您可以在 ForEach 中引用每个 course
的 isToggled
,如下所示:
ForEach(courses) { course in
Section(header: Text(course.title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(course.courseName, id: \.name) { item in
/// here!
Toggle(isOn: course.isToggled, label: {
Text(item.name)
})
}
}
}
但是,这是行不通的。 course.isToggled
是 Bool
,而不是 Toggle 期望的 Binding<Bool>
。
从哪里可以得到Binding<Bool>
?当然是来自@State var courses: [Course]
! 抱歉双关语
Binding<>
部分来自@State
声明。
标有 @State
的属性,例如您的 @State var courses: [Course]
,包括具有 Binding<>
类型的 projectedValue
。
您可以通过向 属性 添加 $
来访问 projectedValue
。所以,如果你写 $courses
,那将有类型 Binding<[Course]>
.
但是,您的切换需要 Binding<Bool>
,而不是 Binding<[Course]>
。
这是 Bool
部分的用武之地。
您需要将绑定的值 [Course]
替换为 Bool
。好吧,我们之前有一个Bool
,对吧?
struct Course: Codable, Identifiable {
var isToggled = false /// this is a Bool!
每个课程都有一个isToggled
,也就是一个Bool
。从这个答案的前面开始,我们在 ForEach
:
中得到了这个
ForEach(courses) { course in
...
/// getting the Bool, which unfortunately doesn't work (yet)
Toggle(isOn: course.isToggled, label: {
...我们需要以某种方式将 Binding<>
与 Bool
结合起来。这意味着我们必须
- 引用
$courses
(得到Binding<>
)
- 获取每个课程的
isToggled
还有... tada!
$courses[index].isToggled /// has type Binding<Bool>
要得到 index
,我们需要遍历 courses.indices
而不是直接遍历 courses
.
ForEach(courses.indices) { index in
...
/// this works!
Toggle(isOn: $courses[index].isToggled, label: {
然后,只需将旧代码 ForEach
中出现的每个 course
替换为 courses[index]
。这是完整的工作示例:
ForEach(courses.indices) { index in
Section(header: Text(courses[index].title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(courses[index].courseName, id: \.name) { item in
/// $courses[index].isToggled is a Binding<Bool>
Toggle(isOn: $courses[index].isToggled, label: {
Text(item.name)
})
}
}
}
为方便起见,您不必在每次需要当前 course
时都执行 courses[index]
,您可以使用 Array(zip
,如 所示循环 (Int, Course)
。这还会为循环内的每个 Section
分配一个唯一的 id
,因此您添加的任何过渡都会顺利进行。
ForEach(Array(zip(courses.indices, courses)), id: \.1.id) { (index, course) in
Section(header: Text(course.title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(course.courseName, id: \.name) { item in
Toggle(isOn: $courses[index].isToggled, label: {
Text(item.name)
})
}
}
}
好吧 (Int, Course)
实际上是 (Range<Array<Course>.Index>.Element, Course)
但这几乎是一回事。
最终结果:
编辑 Content
中的 isToggled
,而不是 Course
:
ForEach(Array(zip(courses.indices, courses)), id: \.1.id) { (index, course) in
Section(header: Text(course.title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(Array(zip(course.courseName.indices, course.courseName)), id: \.1.id) { (itemIndex, item) in
/// here!
Toggle(isOn: $courses[index].courseName[itemIndex].isToggled, label: {
Text(item.name)
})
}
}
}
希望能把我的问题解释清楚
我想 select 通过切换列表中的一些课程,但无论我尝试过什么都没有用。
我该怎么办?
感谢您的宝贵时间。 最好的, 穆拉特
struct SubjectCardsView: View {
// MARK: - Properties
@State var courses: [Course] = Bundle.main.decode("courses.json")
@State private var toggle: Bool = false
// MARK: - Body
var body: some View {
NavigationView {
List {
ForEach(courses) { course in
Section(header: Text(course.title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(course.courseName, id: \.name) { item in
Toggle(isOn: $toggle, label: {
Text(item.name)
})
}
}
}
}
.listStyle(InsetGroupedListStyle())
.navigationBarTitle("Choose your subject", displayMode: .inline).font(.system(size: 16, weight: .medium, design: .rounded))
.navigationBarItems(leading: Button(action: {
}, label: {
Text("Cancel")
}), trailing: Button(action: {
}, label: {
Text("Save")
}))
} // NavigationView
}
}
课程部分!
import Foundation
import SwiftUI
struct Course: Codable, Identifiable {
var id: Int
var title: String
var subjectCount: String
var courseName: [Content]
var isToggled = false
private var imageName: String
var image: Image {
Image(imageName)
}
enum LessonSegment: String, CaseIterable, Identifiable {
case overview
case resources
var id: String { self.rawValue }
}
enum CodingKeys: String, CodingKey {
case id
case title
case subjectCount
case imageName
case courseName
}
}
struct Content: Codable {
var id: Int
var name: String
var content: String
var assessment: String
var notify: String
}
你的 @State private var toggle: Bool = false
没有意义。你有很多课程,而不是一门课程。每门课程都应该有自己的开关 on/off,这是你开始做的:
struct Course: Codable, Identifiable {
var isToggled = false /// here!
...
}
要使用它,您可以在 ForEach 中引用每个 course
的 isToggled
,如下所示:
ForEach(courses) { course in
Section(header: Text(course.title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(course.courseName, id: \.name) { item in
/// here!
Toggle(isOn: course.isToggled, label: {
Text(item.name)
})
}
}
}
但是,这是行不通的。 course.isToggled
是 Bool
,而不是 Toggle 期望的 Binding<Bool>
。
从哪里可以得到Binding<Bool>
?当然是来自@State var courses: [Course]
! 抱歉双关语
Binding<>
部分来自@State
声明。
标有 @State
的属性,例如您的 @State var courses: [Course]
,包括具有 Binding<>
类型的 projectedValue
。
您可以通过向 属性 添加 $
来访问 projectedValue
。所以,如果你写 $courses
,那将有类型 Binding<[Course]>
.
但是,您的切换需要 Binding<Bool>
,而不是 Binding<[Course]>
。
这是 Bool
部分的用武之地。
您需要将绑定的值 [Course]
替换为 Bool
。好吧,我们之前有一个Bool
,对吧?
struct Course: Codable, Identifiable {
var isToggled = false /// this is a Bool!
每个课程都有一个isToggled
,也就是一个Bool
。从这个答案的前面开始,我们在 ForEach
:
ForEach(courses) { course in
...
/// getting the Bool, which unfortunately doesn't work (yet)
Toggle(isOn: course.isToggled, label: {
...我们需要以某种方式将 Binding<>
与 Bool
结合起来。这意味着我们必须
- 引用
$courses
(得到Binding<>
) - 获取每个课程的
isToggled
还有... tada!
$courses[index].isToggled /// has type Binding<Bool>
要得到 index
,我们需要遍历 courses.indices
而不是直接遍历 courses
.
ForEach(courses.indices) { index in
...
/// this works!
Toggle(isOn: $courses[index].isToggled, label: {
然后,只需将旧代码 ForEach
中出现的每个 course
替换为 courses[index]
。这是完整的工作示例:
ForEach(courses.indices) { index in
Section(header: Text(courses[index].title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(courses[index].courseName, id: \.name) { item in
/// $courses[index].isToggled is a Binding<Bool>
Toggle(isOn: $courses[index].isToggled, label: {
Text(item.name)
})
}
}
}
为方便起见,您不必在每次需要当前 course
时都执行 courses[index]
,您可以使用 Array(zip
,如 (Int, Course)
。这还会为循环内的每个 Section
分配一个唯一的 id
,因此您添加的任何过渡都会顺利进行。
ForEach(Array(zip(courses.indices, courses)), id: \.1.id) { (index, course) in
Section(header: Text(course.title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(course.courseName, id: \.name) { item in
Toggle(isOn: $courses[index].isToggled, label: {
Text(item.name)
})
}
}
}
好吧 (Int, Course)
实际上是 (Range<Array<Course>.Index>.Element, Course)
但这几乎是一回事。
最终结果:
编辑 Content
中的 isToggled
,而不是 Course
:
ForEach(Array(zip(courses.indices, courses)), id: \.1.id) { (index, course) in
Section(header: Text(course.title).font(.system(size: 15, weight: .medium, design: .rounded)).foregroundColor(.blue)) {
ForEach(Array(zip(course.courseName.indices, course.courseName)), id: \.1.id) { (itemIndex, item) in
/// here!
Toggle(isOn: $courses[index].courseName[itemIndex].isToggled, label: {
Text(item.name)
})
}
}
}