如何通过代码还原SwiftUI List单元格的滑动操作?
后台时重置SwiftUI List单元格滑动状态
可行,有两种主流实现方式,分别适配纯SwiftUI场景和需要底层UIKit控制的场景:
方法一:纯SwiftUI状态驱动重置
通过给单元格附加可变标识,触发视图重绘来自动收起滑动操作:
struct ContentView: View { @Environment(\.scenePhase) private var scenePhase @State private var items = ["Item 1", "Item 2", "Item 3"] @State private var resetSwipeTrigger = false var body: some View { List { ForEach(items, id: \.self) { item in Text(item) .swipeActions(edge: .trailing) { Button(role: .destructive) { // 执行删除逻辑 } label: { Label("删除", systemImage: "trash") } } .swipeActions(edge: .leading) { Button { // 执行标记逻辑 } label: { Label("标记", systemImage: "checkmark") } } // 利用id变化触发单元格重绘,自动收起滑动状态 .id("\(item)-\(resetSwipeTrigger)") } } .onChange(of: scenePhase) { newPhase in if newPhase == .background { resetSwipeTrigger.toggle() } } } }
原理:当应用进入后台时,切换resetSwipeTrigger状态,SwiftUI会识别到单元格的id发生变化,重新渲染单元格,此时滑动展开的操作按钮会自动收起。
方法二:UIKit底层控制(更精准)
直接操作UITableView的API,主动收起滑动的行操作:
struct ResetableSwipeList: UIViewRepresentable { var items: [String] var onDelete: (String) -> Void var onMark: (String) -> Void func makeUIView(context: Context) -> UITableView { let tableView = UITableView() tableView.delegate = context.coordinator tableView.dataSource = context.coordinator tableView.register(UITableViewCell.self, forCellReuseIdentifier: "SwipeCell") // 监听应用进入后台的通知 NotificationCenter.default.addObserver( context.coordinator, selector: #selector(Coordinator.resetAllSwipeActions), name: UIApplication.didEnterBackgroundNotification, object: nil ) return tableView } func updateUIView(_ uiView: UITableView, context: Context) { uiView.reloadData() } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UITableViewDelegate, UITableViewDataSource { private let parent: ResetableSwipeList init(_ parent: ResetableSwipeList) { self.parent = parent } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { parent.items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "SwipeCell", for: indexPath) cell.textLabel?.text = parent.items[indexPath.row] return cell } // 配置右侧滑动操作 func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let deleteAction = UIContextualAction(style: .destructive, title: "删除") { [weak self] _, _, completion in guard let self = self else { return } self.parent.onDelete(self.parent.items[indexPath.row]) completion(true) } deleteAction.image = UIImage(systemName: "trash") return UISwipeActionsConfiguration(actions: [deleteAction]) } // 配置左侧滑动操作 func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let markAction = UIContextualAction(style: .normal, title: "标记") { [weak self] _, _, completion in guard let self = self else { return } self.parent.onMark(self.parent.items[indexPath.row]) completion(true) } markAction.image = UIImage(systemName: "checkmark") markAction.backgroundColor = .systemGreen return UISwipeActionsConfiguration(actions: [markAction]) } // 重置所有滑动状态 @objc func resetAllSwipeActions() { guard let visibleIndexPaths = tableView.indexPathsForVisibleRows else { return } for indexPath in visibleIndexPaths { tableView.closeRowActions(at: indexPath) } } } }
原理:通过UIViewRepresentable封装UITableView,监听后台通知后,调用tableView.closeRowActions(at:)主动收起每个可见单元格的滑动操作,这种方式可以精准控制状态,不会触发额外的视图重绘。
内容的提问来源于stack exchange,提问作者Reinhard Männer
相关产品推荐
相关产品推荐

