Привязка в SwiftUI не работает внутри цикла - PullRequest
1 голос
/ 27 апреля 2020

Для моего понимания я написал следующий код, который расширяет / сворачивает раздел внутри списка.

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 Ответ

1 голос
/ 27 апреля 2020

Это происходит из-за statically_ranged_ForEach ... как я понял здесь, в SO это наиболее запутанная концепция в SwiftUI ... в любом случае - решение состоит в использовании динамического c контейнера явных моделей для секций.

Вот упрощенная рабочая демонстрация вашего кода (но идея должна легко адаптироваться к вашим не предоставленным компонентам).

Протестировано с Xcode 11.4 / iOS 13.4

demo

// 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)
              }
            }
          }
        }
      }
    }
  }
}
...