在列表中切换选择 - 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 控件在ForEachcourseName 所以有点不清楚。其次,您是坚持使用Int id 还是可以使用更独特的东西,例如 UUID? 每个 courseName 都有一个切换开关,因此我可以了解选择了哪个。选择后,将在内容视图中保存和过滤。我尝试使用 UUID 和 Int id,但它们不起作用。 【参考方案1】:

您的@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]>

但是,您的切换需要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&lt;Array&lt;Course&gt;.Index&gt;.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的主要内容,如果未能解决你的问题,请参考以下文章

如何删除(切换)已选择的“活动”班级列表

具有切换子视图和选择手势的列表项

选择导航列表项时需要切换“活动”类

如果单击两次而不在 vue nuxt 应用程序中切换,如何隐藏列表中的元素

在fastReport中怎样使用自定义的纸张大小

使用列表和数组进行切换和大小写