SwiftUI 中的绑定无法在循环内工作

Posted

技术标签:

【中文标题】SwiftUI 中的绑定无法在循环内工作【英文标题】:Binding in SwiftUI fails to work inside of a loop 【发布时间】:2020-04-27 18:02:00 【问题描述】:

根据我的理解,我编写了以下代码,用于展开/折叠列表中的一个部分。

struct WORKING_CollapsableListView: View 
  @State var sectionExpansionStates = [true, true, true]

  var body: some View 
    VStack 
      List 
          Section(header: CollapsableSectionHeader(expansionState: self.$sectionExpansionStates[0])) 
            if self.sectionExpansionStates[0] 
              ForEach(0..<10)  item in
                Text("\(item) is \(self.sectionExpansionStates[0] ? "Expanded" : "Collapsed")")
                  .frame(height: self.sectionExpansionStates[0] ? 10 : 10)
              
            
          

        Section(header: CollapsableSectionHeader(expansionState: self.$sectionExpansionStates[1])) 
          if self.sectionExpansionStates[1] 
            ForEach(0..<10)  item in
              Text("\(item) is \(self.sectionExpansionStates[1] ? "Expanded" : "Collapsed")")
                .frame(height: self.sectionExpansionStates[1] ? 10 : 10)
            
          
        
        Section(header: CollapsableSectionHeader(expansionState: self.$sectionExpansionStates[2])) 
          if self.sectionExpansionStates[2] 
            ForEach(0..<10)  item in
              Text("\(item) is \(self.sectionExpansionStates[2] ? "Expanded" : "Collapsed")")
                .frame(height: self.sectionExpansionStates[2] ? 10 : 10)
            
          
        
      
    
  


struct CollapsableSectionHeader: View 
  @Binding var expansionState: Bool

  var body: some View 
    Button(action: 
      self.expansionState.toggle()
    ) 
      Text("HEADER: \(expansionState ? "Expanded" : "Collapsed")")
        .bold()
    
  

这按预期工作。但是,以下代码不起作用。我所做的只是用ForEach 替换了多个部分。这段代码的行为应该是相同的,但是当我点击部分标题时没有任何反应。我错过了什么?好像绑定不起作用。

struct NOT_WORKING_CollapsableListView: View 
  @State var sectionExpansionStates = [true, true, true]

  var body: some View 
    VStack 
      List 
        ForEach(0 ..< 3)  section in
          Section(header: CollapsableSectionHeader(expansionState: self.$sectionExpansionStates[section])) 
            if self.sectionExpansionStates[section] 
              ForEach(0..<10)  item in
                Text("\(item) is \(self.sectionExpansionStates[section] ? "Expanded" : "Collapsed")")
                  .frame(height: self.sectionExpansionStates[section] ? 10 : 10)
              
            
          
        
      
    
  

【问题讨论】:

【参考方案1】:

这是由于 statically_ranged_ForEach... 正如我在这里所经历的那样,它是 SwiftUI 中最令人困惑的概念。无论如何 - 解决方案是对部分使用显式模型的动态容器。

这是您的代码的简化工作演示(但这个想法应该很容易被您未提供的组件采用)。

使用 Xcode 11.4 / ios 13.4 测试

// simple demo model for sections
struct SectionModel: Identifiable 
    let id: Int
    var expanded = true


struct TestCollapsableListView: View 
  // dynamic container with model, state is triggered
  @State var sections = [SectionModel(id: 0), SectionModel(id: 1), SectionModel(id: 2)]

  var body: some View 
    VStack 
      List 
        ForEach(sections)  section in
          Section(header: Button("Section \(section.id)")  self.sections[section.id].expanded.toggle() ) 
            if section.expanded 
              ForEach(0..<10)  item in
                Text("\(item) is \(section.expanded ? "Expanded" : "Collapsed")")
                  .frame(height: section.expanded ? 10 : 10)
              
            
          
        
      
    
  

【讨论】:

谢谢!哇。这令人难以置信。在我的实际代码中,我使用了类似的状态模型,但我现在看到的唯一区别是我使用的是 ForEach 中的索引,而不是 section.id,它有效!这件事太微妙了,我自己是想不通的。

以上是关于SwiftUI 中的绑定无法在循环内工作的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI ListView 没有访问 ForEach 循环

ForEach 中的 SwiftUI 索引超出范围

Swift和SwiftUI

在 ForEach 循环中绑定时,如何阻止 SwiftUI TextField 失去焦点?

使用 Binding 确定 SwiftUI 中的字符串更改

表单内 Swift 中的选择器控件有啥问题?