IndexSet ссылается на индекс раздела вместо строки - PullRequest
3 голосов
/ 14 июня 2019

Я хочу реализовать функцию SwipeUI для удаления на SwiftUI Section с помощью модификатора .onDelete.Проблема в том, что он всегда удаляет первый элемент в списке.

В моем представлении есть список с динамическими разделами, созданными с помощью ForEach.

struct SetListView : View {

    var setlist: Setlist
    var body : some View {

        List { 
            ForEach(setlist.sets) { 
                 SetSection(number: $0.id, songs: $0.songs) 
            }
        }
        .listStyle(.grouped)
    }
}

В каждом разделе естьеще ForEach для создания динамических строк:

private struct SetSection : View {

    var number: Int
    @State var songs: [Song]

    var body : some View {
        Section (header: Text("Set \(number)"), footer: Spacer()) {
            ForEach(songs) { song in
                SongRow(song: song)
            }
            .onDelete { index in
                self.songs.remove(at: index.first!)
            }
        }
    }
}

Во время отладки я обнаружил, что IndexSet ссылается на текущий раздел, а не на строку.Поэтому при удалении элементов из первого раздела всегда удаляется первый элемент (так как индекс для первого раздела равен 0).

Это ошибка в SwiftUI?

Если нет, то как я могу получить индекс для строки?

Ответы [ 2 ]

4 голосов
/ 18 июня 2019

У меня была точно такая же проблема.Оказывается, реализация SwiftUI (текущая?) Не распознает вложенные списки.Это означает, что каждый SetSection в вашем List интерпретируется как одна строка, даже если у вас есть ForEach с фактическими SongRow с.Следовательно, IndexSet (index.first!) всегда возвращает ноль.

Я также заметил, что даже при плоской иерархии, такой как ..

List {
   Section {
       ForEach(...) {
          ...
       }
   }
   Section {
       ForEach(...) {
          ...
       }
   }
}

.. отдельные строки нельзя перемещать между разделами.Это также верно при непосредственном использовании двух ForEach, то есть без оболочки Section.

Вероятно, нам следует подать отчет по каждому явлению.

0 голосов
/ 19 июля 2019

Проще говоря, решение этой проблемы состоит в том, чтобы передать раздел методу удаления следующим образом:

  1. Принятие RandomAccessCollection в исходных данных.
  2. Привязка разделаво внешнем ForEach, а затем используя его во внутреннем ForEach, передав его методу удаления:
List {
  ForEach(someGroups.indices) { section in
    bind(self.someGroups[section]) { someGroup in
      Section(header: Text(someGroup.displayName)) {
        ForEach(someGroup.numbers) { number in
          Text("\(number)")
        }
        .onDelete { self.delete(at: $0, in: section) }
      }
    }
  }
}

func delete(at offsets: IndexSet, in section: Int) {
  print("\(section), \(offsets.first!)")
}

Полный, надуманный рабочий пример

( Также доступно в форме Gist для удобства ):

import SwiftUI

func bind<Value, Answer>(_ value: Value, to answer: (Value) -> Answer) -> Answer { answer(value) }

struct Example: View {

  struct SomeGroup: Identifiable, RandomAccessCollection {
    typealias Indices = CountableRange<Int>
    public typealias Index = Int;
    var id: Int
    var displayName: String
    var numbers: [Int]

    public var endIndex: Index {
      return numbers.count - 1
    }

    public var startIndex: Index {
      return 0
    }

    public subscript(position: Int) -> Int {
      get { return numbers[position] }
      set { numbers[position] = newValue }
    }

  }

  var someGroups: [SomeGroup] = {
    return [
      SomeGroup(id: 0, displayName: "First", numbers: [1, 2, 3, 4]),
      SomeGroup(id: 1, displayName: "Second", numbers: [1, 3, 5, 7])
    ]
  }()

  var body: some View {
    List {
      ForEach(someGroups.indices) { section in
        bind(self.someGroups[section]) { someGroup in
          Section(header: Text(someGroup.displayName)) {
            ForEach(someGroup.numbers) { number in
              Text("\(number)")
            }
            .onDelete { self.delete(at: $0, in: section) }
          }
        }
      }
    }
    .listStyle(.grouped)
  }

  func delete(at offsets: IndexSet, in section: Int) {
    print("\(section), \(offsets.first!)")
  }

}

Большое спасибо @ rob-mayoff , который указал мне правильное направление дляэто решение через твиттер!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...