切换列表中的选择-SwiftUI [英] Toggle selection in a list - SwiftUI
问题描述
我希望我能清楚地解释我的问题.
我想通过切换从列表中选择一些课程,但是我尝试过的所有方法都行不通.
我该怎么办?
谢谢您的时间.最好的穆拉特
struct SubjectCardsView:查看{//MARK:-属性@州var课程:[Course] = Bundle.main.decode(" courses.json")@State私人var切换:Bool = false//标记:-正文var body:some View {NavigationView {列表 {ForEach(courses){当然,区段(标题:文本(course.title).font(.system(大小:15,权重:.medium,设计:.rounded)).foregroundColor(.blue)){ForEach(course.courseName,id:\.name){Toggle(isOn:$ toggle,label:{文字(item.name)})}}}}.listStyle(InsetGroupedListStyle()).navigationBarTitle(选择主题",displayMode:.inline).font(.system(大小:16,权重:.medium,设计:.rounded)).navigationBarItems(前导:按钮(操作:{}, 标签: {文字(取消")}),结尾:Button(action:{}, 标签: {文字(保存")}))}//NavigationView}}
课程部分!
import Foundation导入SwiftUI结构课程:可编码,可识别{var id:Intvar标题:字符串var subjectCount:字符串var courseName:[内容]var isToggled = false私人var imageName:字符串var image:图片{图片(imageName)}枚举LessonSegment:字符串,CaseIterable,可识别{案例概述案例资源var id:字符串{self.rawValue}}枚举CodingKeys:字符串,CodingKey {案例ID案例标题案例subjectCount案例imageName案例课程名称}}结构内容:可编码{var id:Int变量名称:字符串var内容:字符串var评估:字串var notify:字符串}
您的 @State私有var切换:Bool = false
没有任何意义.您有很多课程,而不是一门课程.每门课程都应该有自己的开/关,这就是您开始使用的方法:
struct课程:可编码,可识别{var isToggled = false///在这里!...}
要使用此功能,您可以在ForEach中引用每个课程
的 isToggled
,如下所示:
ForEach(courses){当然是区段(标题:文本(course.title).font(.system(大小:15,权重:.medium,设计:.rounded)).foregroundColor(.blue)){ForEach(course.courseName,id:\.name){/// 这里!切换(isOn:course.isToggled,标签:{文字(item.name)})}}}
但是,这行不通. course.isToggled
是 Bool
,而不是Toggle期望的 Binding< Bool>
.
在哪里可以获得 Binding< Bool>
?来自 @State var课程:当然,[课程]
!对不起,双关语
Binding<>
部分来自 @State
声明.
标有 @State
的属性,例如您的 @State var课程:[课程]
,包括一个
但是,您的切换开关期望使用 Binding< Bool>
,而不是 Binding< [Course]>
.
这是 Bool
部分出现的地方.
您将需要用 Bool
替换Binding的值 [Course]
.好吧,我们之前有一个 Bool
,对吧?
struct课程:可编码,可识别{var isToggled = false///这是一个布尔!
每门课程都有一个 isToggled
,它是一个 Bool
.从此答案的较早版本开始,我们就在 ForEach
:
ForEach(courses){当然是...///正在获取Bool,但不幸的是,该Bool无法正常工作(尚未)切换(isOn:course.isToggled,标签:{
...我们需要以某种方式将 Binding<>
与 Bool
组合在一起.这意味着我们必须
- 引用
$ courses
(以获取Binding<>
) - 获取每个课程的
isToggled
还有...多田!
$ courses [index] .isToggled///具有Binding< Bool>类型;
要获取 index
,我们需要遍历 courses.indices
,而不是直接循环遍历 courses
.
ForEach(courses.indices){...///这行得通!切换(isOn:$ courses [index] .isToggled,标签:{
然后,只需用 courses [index]
替换旧代码的 ForEach
中每次出现的 course
.这是完整的工作示例:
ForEach(courses.indices){节(标题:文本(courses [index] .title).font(.system(大小:15,权重:.medium,设计:.rounded)).foregroundColor(.blue)){ForEach(courses [index] .courseName,id:\.name){///$ courses [index] .isToggled是Binding< Bool>切换(isOn:$ courses [index] .isToggled,标签:{文字(item.name)})}}}
为方便起见,您不必每次都需要当前的 course
时就要做 courses [index]
,您可以使用 Array(zip
,如此答案所示,以遍历(Int,Course)
.还为循环内的每个 Section
分配了唯一的 id
,因此您添加的任何过渡都可以顺利实现.
ForEach(Array(zip(zip(courses.indices,courses)),id:\ .1.id){(索引,课程)在区段(标题:文本(course.title).font(.system(大小:15,权重:.medium,设计:.rounded)).foregroundColor(.blue)){ForEach(course.courseName,id:\.name){切换(isOn:$ courses [index] .isToggled,标签:{文字(item.name)})}}}
好(内部课程)
实际上是(Range< Array< Course> .Index> .Element,课程)
,但这几乎是同一回事
最终结果:
在 Content
中而不是 Course
内编辑 isToggled
:
ForEach(Array(zip(zip(courses.indices,courses)),id:\ .1.id){(索引,课程)在区段(标题:文本(course.title).font(.system(大小:15,权重:.medium,设计:.rounded)).foregroundColor(.blue)){ForEach(Array(zip(zip(course.courseName.indices,course.courseName)),id:\ .1.id){(itemIndex,item)在/// 这里!切换(isOn:$ courses [index] .courseName [itemIndex] .isToggled,标签:{文字(item.name)})}}}
I hope I can explain my question clearly.
I want to select some courses from list via toggle but whatever I've tried it didn't work.
What am I supposed to do?
Thank you for your time. Bests, Murat
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
}
}
Course part!
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
}
Your @State private var toggle: Bool = false
doesn't make sense. You have many courses, not a single course. Each course should have it's own toggle on/off, which is what you started to do with:
struct Course: Codable, Identifiable {
var isToggled = false /// here!
...
}
To use this, you can reference each course
's isToggled
inside the ForEach, like this:
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)
})
}
}
}
However, this won't work. course.isToggled
is a Bool
, not a Binding<Bool>
, which the Toggle expects.
Where can you get Binding<Bool>
? From the @State var courses: [Course]
, of course! sorry for pun
The Binding<>
part comes from the @State
declaration.
Properties that are marked with @State
, like your @State var courses: [Course]
, include a projectedValue
that has the Binding<>
type.
You can access the projectedValue
by adding a $
to the property. So, if you write $courses
, that will have type Binding<[Course]>
.
But, your toggle expects Binding<Bool>
, not Binding<[Course]>
.
This is where the Bool
part comes in.
You will need to replace the Binding's value, [Course]
, with a Bool
. Well, we had a Bool
before, right?
struct Course: Codable, Identifiable {
var isToggled = false /// this is a Bool!
Each course has a isToggled
, which is a Bool
. From earlier on in this answer, we got this inside the ForEach
:
ForEach(courses) { course in
...
/// getting the Bool, which unfortunately doesn't work (yet)
Toggle(isOn: course.isToggled, label: {
... We need to somehow combine the Binding<>
with the Bool
. This means that we must
- reference
$courses
(to get theBinding<>
) - get each courses'
isToggled
And... tada!
$courses[index].isToggled /// has type Binding<Bool>
To get index
, we'll need to loop over courses.indices
instead of directly looping over courses
.
ForEach(courses.indices) { index in
...
/// this works!
Toggle(isOn: $courses[index].isToggled, label: {
Then, just replace every occurrence of course
in your old code's ForEach
with courses[index]
. Here's the full working example:
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)
})
}
}
}
As a convenience so you don't have to do courses[index]
every time you want the current course
, you can use Array(zip
as shown in this answer to loop over a (Int, Course)
. This also assigns a unique id
for every Section
inside the loop, so any transitions you add will work out smoothly.
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)
})
}
}
}
Well (Int, Course)
is actually (Range<Array<Course>.Index>.Element, Course)
but that's pretty much the same thing.
Final result:
Edit for isToggled
inside Content
, not 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)
})
}
}
}
这篇关于切换列表中的选择-SwiftUI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!