SwiftUI中如何实现自定义滑动操作?UIKit方案尝试失败
搞定SwiftUI自定义滑动操作的问题
嘿,你的代码里有几个明显的问题导致自定义滑动没生效,我来帮你梳理下,再给你两种可行的解决方案:
首先说下你代码里的核心问题:
- 你把
UITableView的代理方法直接写在了全局的init()块里,这完全不对啊!init是初始化方法,不是类,根本不能用来重写UIKit的代理方法,这些方法得放在一个遵循UITableViewDelegate的类里才行。 - SwiftUI的默认
List只提供了基础的删除操作,要实现自定义滑动,要么用SwiftUI原生的新API(iOS15+可用),要么自己封装UITableView来完全控制滑动行为。
下面给你两种方案,按需选择:
方案1:用SwiftUI原生的.swipeActions(推荐,iOS15+)
如果你的项目支持iOS15及以上版本,直接用这个原生修饰符就够了,不用折腾UIKit:
import SwiftUI struct TestView: View { @StateObject var appointmentsViewModel = AppointmentsViewModel() // 假设你有对应的ViewModel var body: some View { NavigationStack { // iOS16+用这个,iOS15版本用NavigationView List { ForEach(appointmentsViewModel.appointments) { appointment in Row_Appointments(appointment: appointment) .swipeActions(edge: .trailing) { Button { print("标记为重要:\(appointment.id)") // 这里添加你的业务逻辑 } label: { Label("Important", systemImage: "pencil") } .tint(Color(hue: 0.0861, saturation: 0.76, brightness: 0.94)) } } .onDelete(perform: delete) } .navigationTitle("预约") } } private func delete(at offsets: IndexSet) { appointmentsViewModel.appointments.remove(atOffsets: offsets) } } // 以下是假设的相关结构,你可以替换成自己的实现 struct Appointment: Identifiable { let id = UUID() let title: String } struct Row_Appointments: View { let appointment: Appointment var body: some View { Text(appointment.title) } } class AppointmentsViewModel: ObservableObject { @Published var appointments: [Appointment] = [ Appointment(title: "团队会议"), Appointment(title: "看医生") ] }
方案2:封装UITableView兼容旧版本(iOS15以下)
如果要支持更早的iOS版本,就得通过UIViewRepresentable桥接UITableView,自己控制滑动逻辑:
import SwiftUI import UIKit struct CustomTableView: UIViewRepresentable { @ObservedObject var viewModel: AppointmentsViewModel let onDelete: (IndexSet) -> Void func makeUIView(context: Context) -> UITableView { let tableView = UITableView() tableView.delegate = context.coordinator tableView.dataSource = context.coordinator // 注册cell,若用自定义cell可替换为对应的类或xib tableView.register(UITableViewCell.self, forCellReuseIdentifier: "AppointmentCell") return tableView } func updateUIView(_ uiView: UITableView, context: Context) { uiView.reloadData() } // 用Coordinator处理UITableView的代理和数据源 func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UITableViewDelegate, UITableViewDataSource { let parent: CustomTableView init(_ parent: CustomTableView) { self.parent = parent } // 返回列表行数 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { parent.viewModel.appointments.count } // 配置cell内容 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "AppointmentCell", for: indexPath) let appointment = parent.viewModel.appointments[indexPath.row] cell.textLabel?.text = appointment.title // 若要加载SwiftUI自定义Row,可通过UIHostingController包装,这里简化处理 return cell } // 核心:自定义滑动操作 func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { // 「重要」操作 let importantAction = UIContextualAction(style: .normal, title: "Important") { [weak self] (_, _, completion) in guard let self = self else { return } let appointment = self.parent.viewModel.appointments[indexPath.row] print("标记为重要:\(appointment.id)") completion(true) } importantAction.backgroundColor = UIColor(hue: 0.0861, saturation: 0.76, brightness: 0.94, alpha: 1.0) importantAction.image = UIImage(systemName: "pencil") // 删除操作 let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { [weak self] (_, _, completion) in guard let self = self else { return } self.parent.onDelete(IndexSet(integer: indexPath.row)) completion(true) } return UISwipeActionsConfiguration(actions: [deleteAction, importantAction]) } } } // 在View中使用自定义TableView struct TestView: View { @StateObject var viewModel = AppointmentsViewModel() var body: some View { NavigationView { CustomTableView(viewModel: viewModel, onDelete: delete) .navigationTitle("预约") } } private func delete(at offsets: IndexSet) { viewModel.appointments.remove(atOffsets: offsets) } } // 同样需要定义Appointment、Row_Appointments和AppointmentsViewModel
再回头说下你原代码的问题
你把UITableView的代理方法写在全局init()里,这完全是语法错误——这种代理方法必须放在一个遵循UITableViewDelegate的类中,比如方案2里的Coordinator。而且SwiftUI的默认List是封装好的组件,不会让你直接修改底层的UITableView代理,所以要么用原生API,要么自己封装。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

