在列表中切换选择 - SwiftUI
Posted
技术标签:
【中文标题】在列表中切换选择 - SwiftUI【英文标题】:Toggle selection in a list - SwiftUI 【发布时间】:2021-04-12 19:06:46 【问题描述】:我希望我能清楚地解释我的问题。
我想通过切换从列表中选择一些课程,但无论我尝试过什么都没有用。
我该怎么办?
感谢您的宝贵时间。 最好的, 穆拉特
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
【问题讨论】:
你能附上Course
的代码吗?
是的。我编辑了原始消息。
所以你想切换是否每个Content
被选中? Content
上是否有某个属性应该响应切换?看起来你在Course
上有一个isToggled
,但你的Toggle
控件在ForEach
下courseName
所以有点不清楚。其次,您是坚持使用Int
id 还是可以使用更独特的东西,例如 UUID?
每个 courseName 都有一个切换开关,因此我可以了解选择了哪个。选择后,将在内容视图中保存和过滤。我尝试使用 UUID 和 Int id,但它们不起作用。
【参考方案1】:
您的@State private var toggle: Bool = false
没有意义。你有很多课程,而不是一门课程。每门课程都应该有它自己的开关,这是你开始做的:
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
还有……多多!
$courses[index].isToggled /// has type Binding<Bool>
要获得index
,我们需要循环遍历courses.indices
,而不是直接循环遍历courses
。
ForEach(courses.indices) index in
...
/// this works!
Toggle(isOn: $courses[index].isToggled, label:
然后,只需用 courses[index]
替换旧代码的 ForEach
中出现的所有 course
。这是完整的工作示例:
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
,如this answer 所示循环遍历(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)
)
【讨论】:
感谢您编辑我的问题和您的回答。有用。快两天了,我一直在努力。我今天学到了一些东西。 :) @muradi 我为我的回答添加了一些额外的说明:) 再次感谢您。我想再问一个问题。每门课程都有两个或更多课程名称,并且切换再次作为一个块工作。很抱歉打扰您。 @muradi 当然,这是什么? 我正在尝试上传屏幕共享。 link以上是关于在列表中切换选择 - SwiftUI的主要内容,如果未能解决你的问题,请参考以下文章