Есть ли способ удалить строку в списке в SwiftUI? - PullRequest
4 голосов
/ 12 июня 2019

Я создал тихий простой список в SwiftUI и хочу сделать его редактируемым, как tableView в UIKit.Я хочу удалить строку из списка всем известным жестом (проведите пальцем справа налево).

Я попытался сделать это с помощью кнопки над списком, но это не выглядит красиводля моего приложения это практически невозможно.

struct singleIsland: Identifiable {
    let id: Int
    let name:String
}

var islands = [
singleIsland(id: 0, name: "Wangerooge"),
singleIsland(id: 1, name: "Spiekeroog"),
singleIsland(id: 2, name: "Langeoog")
]

var body: some View {
    VStack {

        List(islands) { island in
            Text(island.name)
        }
    }
}

Ответы [ 3 ]

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

Да, это очень просто с SwiftUI.

Обновление вашего кода следующим образом ...

struct SingleIsland: Identifiable {
    let id: Int
    let name:String
}

struct IslandListView: View {
    @State private var islands = [
        SingleIsland(id: 0, name: "Wangerooge"),
        SingleIsland(id: 1, name: "Spiekeroog"),
        SingleIsland(id: 2, name: "Langeoog")
    ]

    var body: some View {
        List {
            ForEach(islands.identified(by: \.name)) { island in
                Text(island.name)   
            }.onDelete(perform: delete)
        }
    }

    func delete(at offsets: IndexSet) {
        islands.remove(at: offsets)
    }
}

Это позволит вашему виду проводить пальцем, чтобы удалить строки.

Использование @State устанавливает ваше представление в зависимости от массива islands.Любое обновление этого массива приведет к перезагрузке представления.Таким образом, удалив элемент из массива, он оживит изменение в списке.

0 голосов
/ 12 июня 2019

вы не можете сделать это со статическим списком.

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

мы используем вашу структуру:

[...]
struct singleIsland: Identifiable {
    var id: Int
    var name:String
}
[...]

и создайте привязываемый Объект для хранения этих островов

[...]
class IslandStore : BindableObject {

   let didChange = PassthroughSubject<IslandStore, Never>()

   var islands : [singleIsland] {
       didSet { didChange.send(self) }
   }

   init (islands: [singleIsland] = []){
       self.islands = islands
   } 
}
[...]

вам нужно импортировать объединение, чтобы использовать BindableObject

[...]
import SwiftUI
import Combine
[...]

ваш взгляд теперь связывает магазин острова .onDelete (выполнить: удалить) автоматически добавляет движение влево для удаления функции. Мы должны закодировать функцию удаления tho:

[...]
struct ForTesting : View {
    @ObjectBinding var store = IslandStore()
    var body: some View {
        List {

            ForEach(store.islands) { island in
                Text(island.name)
                }.onDelete(perform: delete)

        }
    }

    func delete(at offsets: IndexSet) {

        // theres seems to be a bug that prevents us from using atOffsets
        // so we convert to index
        guard let index = Array(offsets).first else { return }

        store.islands.remove(at: index)
    }
}
[...]

и пока мы добавляем EditButton () и заголовок. Нам нужно обернуть наш список в NavigationView , чтобы сделать это

[...]
struct ForTesting : View {
    @ObjectBinding var store = IslandStore()
    var body: some View {
        NavigationView {
            List {

                ForEach(store.islands) { island in
                    Text(island.name)
                    }.onDelete(perform: delete)
                }
                .navigationBarTitle(Text("Islands"))
                .navigationBarItems(trailing: EditButton())

        }
    }

    func delete(at offsets: IndexSet) {

        // theres seems to be a bug that prevents us from using atOffsets
        // so we convert to index
        guard let index = Array(offsets).first else { return }

        store.islands.remove(at: index)
    }
}
[...]

измените раздел DEBUG, чтобы инициализировать магазин островов, и передайте его на ваш вид:

#if DEBUG

var islands = [
    singleIsland(id: 0, name: "Wangerooge"),
    singleIsland(id: 1, name: "Spiekeroog"),
    singleIsland(id: 2, name: "Langeoog"),
    singleIsland(id: 3, name: "Baltrum")
]

struct ForTesting_Previews : PreviewProvider {
    static var previews: some View {
        ForTesting(store: IslandStore(islands:islands))
    }
}

#endif

viewwithdelete

полный код

0 голосов
/ 12 июня 2019
struct SingleIsland {
    let name: String
}

struct ContentView: View {

    @State var islands = [
        SingleIsland(name: "Wangerooge"),
        SingleIsland(name: "Spiekeroog"),
        SingleIsland(name: "Langeoog")
    ]

    var body: some View {
        List {
            ForEach(islands.identified(by: \.name)) { island in
                Text(island.name)
            }.onDelete(perform: delete)
        }
    }

    private func delete(with indexSet: IndexSet) {
        indexSet.forEach { islands.remove(at: $0) }
    }
}

Обтекание данных в @State гарантирует, что представление перерисовывается при его изменении.


Примечание :

I'mполучение ошибок компилятора, если List построен следующим образом:

List(data) { item in
 [...]
}

Он будет жаловаться, что onDelete не существует для List.

Мой обходной путь должен использоватьForEach внутри List и функции onDelete на нем.

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