#swiftui
#swiftui
Вопрос:
Поскольку OnDelete и onMove являются функциями списка / формы, я не могу их использовать, когда у меня есть пользовательские интерфейсы без них. Я использовал VStack внутри ForEach. Я совсем новичок в SwiftUI и не уверен, как я могу реализовать пользовательский код для OnDelete и onMove.
Вот мой код:
struct Trying: View {
@State private var numbers = [0,1,2,3,4,5,6,7,8,9]
var body: some View {
NavigationView {
VStack (spacing: 10) {
ForEach(numbers, id: .self) { number in
VStack {
Text("(number)")
}
.frame(width: 50, height: 50)
.background(Color.red)
}.onDelete(perform: removeRows)
}
.navigationTitle("Trying")
.navigationBarItems(trailing: EditButton())
}
}
func removeRows(at offsets: IndexSet) {
numbers.remove(atOffsets: offsets)
}
}
То, как это работает прямо сейчас:
Ответ №1:
Вот простая демонстрация возможного подхода к реализации пользовательского удаления (конечно, с move это было бы сложнее из-за перетаскивания, но идея та же). Протестировано с Xcode 12 / iOS 14.
struct DemoCustomDelete: View {
@State private var numbers = [0,1,2,3,4,5,6,7,8,9]
var body: some View {
NavigationView {
VStack (spacing: 10) {
ForEach(numbers, id: .self) { number in
VStack {
Text("(number)")
}
.frame(width: 50, height: 50)
.background(Color.red)
.overlay(
DeleteButton(number: number, numbers: $numbers, onDelete: removeRows)
, alignment: .topTrailing)
}.onDelete(perform: removeRows)
}
.navigationTitle("Trying")
.navigationBarItems(trailing: EditButton())
}
}
func removeRows(at offsets: IndexSet) {
withAnimation {
numbers.remove(atOffsets: offsets)
}
}
}
struct DeleteButton: View {
@Environment(.editMode) var editMode
let number: Int
@Binding var numbers: [Int]
let onDelete: (IndexSet) -> ()
var body: some View {
VStack {
if self.editMode?.wrappedValue == .active {
Button(action: {
if let index = numbers.firstIndex(of: number) {
self.onDelete(IndexSet(integer: index))
}
}) {
Image(systemName: "minus.circle")
}
.offset(x: 10, y: -10)
}
}
}
}
Комментарии:
1. -глядя на ваше решение, мне интересно, будет ли это работать с CoreData? У меня есть lazyHGrid, который показывает результаты запроса выборки. Я не смог понять, как получить рабочую функцию удаления. до того, как я переключился на lazyHGrid, я использовал простой список, и я мог удалить через — private func deleteEvent(offsets: IndexSet) { withAnimation { offsets.map { events[$ 0] }.forEach(moc.delete) сделайте { try moc.save() } catch { пусть NSError = ошибка как NSError FatalError(«Неразрешенная ошибка ( NSError), (NSError.userInfo)») } } }
Ответ №2:
Основываясь на ответе @ Asperi, я просто обобщил его, чтобы принять любую Equatable
последовательность.
struct DeleteButton<T>: View where T: Equatable {
@Environment(.editMode) var editMode
let number: T
@Binding var numbers: [T]
let onDelete: (IndexSet) -> ()
var body: some View {
VStack {
if self.editMode?.wrappedValue == .active {
Button(action: {
if let index = numbers.firstIndex(of: number) {
self.onDelete(IndexSet(integer: index))
}
}) {
Image(systemName: "minus.circle")
}
.offset(x: 10, y: -10)
}
}
}
}
Ответ №3:
Недавно мне понадобилось удалить строку, и я не мог использовать СПИСОК. Вместо этого у меня был вид прокрутки… Но я смог реализовать редактирование для имитации того же поведения при удалении, как если бы это был список. Изначально я не мог заставить свой код работать. Только после того, как я внимательно изучил свою реализацию и поэкспериментировал, я наткнулся на то, почему моя сработала. Я кодирую для iPad, поэтому мой NavigationView использует,
.navigationViewStyle (StackNavigationViewStyle())
Как только я добавил это в NavigationView структуры, при нажатии на кнопку редактирования активируется режим редактирования?.wrappedValue to .active / .inactive
Ниже приведена моя реализация для примера кода выше…
struct Trying: View {
@State var num: Int = 0
@Environment(.editMode) var editMode
@State private var numbers = [0,1,2,3,4,5,6,7,8,9]
var body: some View {
NavigationView {
VStack {
ForEach(numbers, id: .self) { number in
HStack {
if editMode?.wrappedValue == .active {
Button(action: { num = number
removeRows(numbr: num)
}, label: {
Image(systemName: "minus.circle.fill")
.foregroundColor(.red)
})
} // END IF editMode?wrappedValue == .active
Text("(number)")
.frame(width: 50, height: 50)
.background(Color.red)
}
}
// .onDelete(perform: removeRows)
}
.navigationTitle("Trying")
.navigationBarItems(trailing: EditButton())
}
// FOR SOME REASON THIS ALLOWS THE EditButton() to activate editMode without a LIST being present.
.navigationViewStyle(StackNavigationViewStyle())
}
func removeRows(numbr: Int) {
print("removing (numbr)")
}
}
Это выглядит как: