SwiftUI swipeActions 重新加载导致前导空白 space 和滑动中断

SwiftUI swipeActions reload results in leading blank space and broken swipe

我正在尝试使用 swipeActions SwiftUI 修改器设置,如下面的代码所示,但滑动操作被禁用,如此 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: { [=12=] == item }) {
            items.remove(at: index)
        }
        
        let itemsSaved = items
        items = []
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            self.items = itemsSaved
        }
    }
}

预期行为:重新加载的行在每行的开头没有 space 视图,并且可以像以前一样滑动行。

实际行为:每行在行的开头都有一个space视图,您不能像以前那样滑动行。

我还创建了一个示例项目:code and additional video

知道是否有解决方法吗?

谢谢。

我仍然不确定为什么您的实现会导致此行为,除了您完全在两个单独的视图之间切换(ZstackProgressView)。我怀疑来回更改只是将 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: { [=10=] == 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
}