Я пытаюсь использовать настройку модификатора SwiftUI swipeДействия, как показано в приведенном ниже коде, но действие смахивания отключается, как показано на этом gif:
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
if viewModel.items.count > 0 {
ZStack {
List {
ForEach(viewModel.items, id: \.self) { item in
Text(item)
.swipeActions {
Button {
viewModel.removeAction(item: item)
} label: {
Text("Remove")
}
.tint(.orange)
}
}
}
}
} else {
ProgressView()
.foregroundColor(.accentColor)
.scaleEffect(2)
}
}
В модели представления после первого свайпа я бы перезагрузил список из API (пример кода просто имитирует задержку):
extension ContentView {
class ViewModel: ObservableObject {
@Published var items: [String]
init(items: [String]) {
self.items = items
}
func removeAction(item: String) {
if let index = items.firstIndex(where: { $0 == item }) {
items.remove(at: index)
}
let itemsSaved = items
items = []
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.items = itemsSaved
}
}
}
Ожидаемое поведение: у перезагруженных строк нет пробела в начале каждой строки, и строки можно прокручивать, как и раньше.
Фактическое поведение: каждая строка имеет вид пробела в начале строки, вы не можете прокручивать строки, как раньше.
Я также создал пример проекта: код и дополнительный видео.
Любая идея, если есть обходной путь?
Спасибо.





Я до сих пор не уверен, почему ваша реализация вызывает такое поведение, кроме того, что вы полностью переключаетесь между двумя отдельными представлениями (Zstack против ProgressView). Я подозреваю, что изменение туда и обратно просто переводит List в какое-то странное состояние. Однако исправить это просто; поместите условное выражение внутри ZStack:
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
ZStack {
// Move the conitional inside of the ZStack.
// Always use .isEmpty for this sort of test. Faster and
// less resources than count
if !viewModel.items.isEmpty {
List {
// I made Item an Identifiable struct. Deleting items
// identified as .self can lead to issues in a ForEach
ForEach(viewModel.items) { item in
Text(item.name)
.swipeActions {
Button {
viewModel.removeAction(item: item)
} label: {
Text("Remove")
}
.tint(.orange)
}
}
}
} else {
Text("Progress View")
}
}
}
}
extension ContentView {
class ViewModel: ObservableObject {
@Published var items: [Item]
init(items: [Item]) {
self.items = items
}
func removeAction(item: Item) {
if let index = items.firstIndex(where: { $0 == item }) {
items.remove(at: index)
}
let itemsSaved = items
items = []
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.items = itemsSaved
}
}
}
}
// I made this as a data model.
struct Item: Identifiable, Hashable {
var id = UUID()
var name: String
}
Спасибо @Yrb. Я сам поиграл с этим и пришел к такому же выводу, но у меня также есть другие условные выражения (if/else), которые я не могу переместить в ZStack. Например. Возможно, мне придется показать ошибку из API. Интересно, есть ли что-то, что все еще может вызвать сброс List, чтобы восстановить сломанное состояние.
Еще одна вещь, которую я обнаружил, исправлена просто в том, что данные не очищались. То, что вы здесь сделали, не имеет большого смысла. Вы удаляете один элемент, затем удаляете ВСЕ элементы, а затем перезагружаете их. Если вы не удалили их все, а просто позволили обновлению обновить их, у вас нет проблемы. Я предположил, что это MRE, поэтому я не сильно сомневаюсь в логике, когда пытаюсь ответить, если только она не кажется неотъемлемой частью ответа.
Да, спасибо @Yrb. Это взад и вперед не имеет смысла в этом примере проекта, но в приложении, над которым я работаю, это связано с функциями поиска/вызова API/удаления/добавления.
Хорошая мысль о
empty. Кажется, я иногда забываю об этом.