微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在列表中切换选择 - SwiftUI Binding<> 部分来自 @State 声明这就是 Bool 部分的用武之地

如何解决在列表中切换选择 - SwiftUI Binding<> 部分来自 @State 声明这就是 Bool 部分的用武之地

我希望我能清楚地解释我的问题。

我想通过切换从列表中选择一些课程,但我尝试过的任何课程都不起作用。

我该怎么办?

感谢您的时间。 最好的, 穆拉特

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,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 没有意义。你有很多课程,而不是一门课程。每门课程都应该有自己的开/关开关,这是您开始使用的:

struct Course: Codable,Identifiable {
    var isToggled = false /// here!

    ...
}

要使用它,您可以在 ForEach 中引用每个 courseisToggled,如下所示:

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.isToggledBool,而不是 Toggle 所期望的 Binding<Bool>

您从哪里可以获得Binding<Bool>?当然来自@State var courses: [Course]抱歉双关语


Binding<> 部分来自 @State 声明。

标有 @State 的属性,如您的 @State var courses: [Course],包括一个 Binding<> 类型的 projectedValue

您可以通过向属性添加 projectedValue 来访问 $。因此,如果您编写 $courses,则类型为 Binding<[Course]>

Xcode autocompletion for $courses

但是,您的切换需要 Binding<Bool>,而不是 Binding<[Course]>

Toggle(isOn: Binding,label: { Text("A cool toggle") })

这就是 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: {

然后,只需用 course 替换旧代码 ForEach 中出现的所有 courses[index]。这是完整的工作示例:

ForEach(courses.indices) { index in
    Section(header: Text(courses[index].title).font(.system(size: 15,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)
            })
        }
    }
}

为方便起见,您不必每次想要当前的 courses[index] 时都执行 course,您可以使用 this answer 中所示的 Array(zip 循环(Int,Course)。这还会为循环内的每个 id 分配一个唯一的 Section,因此您添加的任何过渡都会顺利进行。

ForEach(Array(zip(courses.indices,courses)),id: \.1.id) { (index,course) in

    Section(header: Text(course.title).font(.system(size: 15,id: \.name) { item  in

            Toggle(isOn: $courses[index].isToggled,label: {
                Text(item.name)
            })
        }
    }
}

好吧,(Int,Course) 实际上是 (Range<Array<Course>.Index>.Element,Course),但这几乎是同一回事。

最终结果:

Toggles inside each row of the ForEach working

isToggled 内编辑 Content,而不是 Course

ForEach(Array(zip(courses.indices,course) in
    Section(header: Text(course.title).font(.system(size: 15,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)
            })
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。