You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在列表单元格滑动时禁用工具栏按钮?

实现列表单元格滑动时禁用工具栏按钮

方案一:通过ObservableObject管理滑动状态(纯SwiftUI)

这种方法通过全局状态管理器跟踪单元格的滑动状态,结合滑动操作的回调和交互事件更新状态,进而控制工具栏按钮的启用状态。

  1. 创建状态管理器
import SwiftUI

class ListSlideStateManager: ObservableObject {
    // 记录当前滑动的单元格索引,nil表示无单元格处于滑动状态
    @Published var currentSwipedIndex: Int?
    
    // 计算属性:快速判断是否有单元格滑动
    var isAnyCellSwiped: Bool {
        currentSwipedIndex != nil
    }
}
  1. 父视图集成状态管理器
struct ContentView: View {
    @StateObject private var slideManager = ListSlideStateManager()
    // 示例数据
    private let items = (1...20).map { Item(id: $0, title: "条目 \($0)") }
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(Array(items.enumerated()), id: \.element.id) { index, item in
                    SwipeableCell(item: item, index: index, slideManager: slideManager)
                }
            }
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button("工具栏操作") {
                        // 执行按钮逻辑
                    }
                    // 根据滑动状态禁用按钮
                    .disabled(slideManager.isAnyCellSwiped)
                }
            }
            // 点击背景取消滑动并重置状态
            .background(
                Color.clear
                    .onTapGesture {
                        slideManager.currentSwipedIndex = nil
                    }
            )
        }
    }
}

// 示例数据模型
struct Item: Identifiable {
    let id: Int
    let title: String
}
  1. 自定义可滑动单元格
struct SwipeableCell: View {
    let item: Item
    let index: Int
    @ObservedObject var slideManager: ListSlideStateManager
    
    var body: some View {
        Text(item.title)
            .swipeActions(edge: .trailing) {
                Button(role: .destructive) {
                    // 执行滑动按钮逻辑(比如删除)
                    slideManager.currentSwipedIndex = nil
                } label: {
                    Label("删除", systemImage: "trash")
                }
                // 滑动按钮出现时,标记当前单元格为滑动状态
                .onAppear {
                    slideManager.currentSwipedIndex = index
                }
            }
            // 点击单元格时取消滑动状态
            .onTapGesture {
                slideManager.currentSwipedIndex = nil
            }
    }
}

方案二:利用UIKit UITableView代理回调(底层原生方式)

如果需要更精准的状态监听,可以直接利用SwiftUI List底层的UITableView代理方法,监听滑动编辑的开始和结束事件:

  1. 自定义UITableView代理扩展
import SwiftUI
import UIKit

class SlideDetectionTableViewDelegate: NSObject, UITableViewDelegate {
    weak var slideManager: ListSlideStateManager?
    
    func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {
        slideManager?.currentSwipedIndex = indexPath.row
    }
    
    func tableView(_ tableView: UITableView, didEndEditingRowAt indexPath: IndexPath?) {
        slideManager?.currentSwipedIndex = nil
    }
}

// 包装UITableView以注入自定义代理
struct SlideDetectingList: UIViewRepresentable {
    @ObservedObject var slideManager: ListSlideStateManager
    let content: () -> List<Never, Never>
    
    func makeUIView(context: Context) -> UITableView {
        let tableView = UITableView()
        tableView.delegate = context.coordinator
        return tableView
    }
    
    func updateUIView(_ uiView: UITableView, context: Context) {}
    
    func makeCoordinator() -> SlideDetectionTableViewDelegate {
        let coordinator = SlideDetectionTableViewDelegate()
        coordinator.slideManager = slideManager
        return coordinator
    }
}
  1. 在父视图中使用自定义List
struct ContentView: View {
    @StateObject private var slideManager = ListSlideStateManager()
    private let items = (1...20).map { Item(id: $0, title: "条目 \($0)") }
    
    var body: some View {
        NavigationStack {
            SlideDetectingList(slideManager: slideManager) {
                List {
                    ForEach(items) { item in
                        Text(item.title)
                            .swipeActions(edge: .trailing) {
                                Button(role: .destructive) {
                                    // 删除逻辑
                                } label: {
                                    Label("删除", systemImage: "trash")
                                }
                            }
                    }
                }
            }
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button("工具栏操作") {
                        // 按钮逻辑
                    }
                    .disabled(slideManager.isAnyCellSwiped)
                }
            }
        }
    }
}

为什么之前的方法无效?

  • .onAppear/.onDisappear:滑动按钮只是在视图内平移,并未被添加/移除出视图层级,因此这两个回调不会触发。
  • GeometryReader:滑动操作属于UIKit的交互动画,不会触发SwiftUI视图的重绘,因此GeometryReader无法捕获帧变化。

内容的提问来源于stack exchange,提问作者Reinhard Männer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 18:23:27