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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:22:45