SwiftUI — swipeActions

swipeActions 是 SwiftUI 中用于为列表项添加滑动操作的修饰符。让我通过示例来详细解释:

1. 基本用法 #

List {
    ForEach(items) { item in
        Text(item.title)
            .swipeActions {
                Button("删除") {
                    // 删除操作
                }
            }
    }
}

2. 完整示例 #

struct ContentView: View {
    @State private var items = ["项目1", "项目2", "项目3"]
    
    var body: some View {
        List {
            ForEach(items, id: \.self) { item in
                Text(item)
                    .swipeActions(edge: .trailing, allowsFullSwipe: true) {
                        Button(role: .destructive) {
                            delete(item)
                        } label: {
                            Label("删除", systemImage: "trash")
                        }
                        
                        Button {
                            share(item)
                        } label: {
                            Label("分享", systemImage: "square.and.arrow.up")
                        }
                        .tint(.blue)
                    }
                    .swipeActions(edge: .leading) {
                        Button {
                            favorite(item)
                        } label: {
                            Label("收藏", systemImage: "star")
                        }
                        .tint(.yellow)
                    }
            }
        }
    }
    
    func delete(_ item: String) {
        if let index = items.firstIndex(of: item) {
            items.remove(at: index)
        }
    }
    
    func share(_ item: String) {
        // 分享操作
    }
    
    func favorite(_ item: String) {
        // 收藏操作
    }
}

3. 实际应用示例 #

邮件列表 #

struct EmailListView: View {
    @State private var emails: [Email] = []
    
    var body: some View {
        List {
            ForEach(emails) { email in
                EmailRow(email: email)
                    .swipeActions(edge: .trailing, allowsFullSwipe: true) {
                        Button(role: .destructive) {
                            deleteEmail(email)
                        } label: {
                            Label("删除", systemImage: "trash")
                        }
                        
                        Button {
                            archiveEmail(email)
                        } label: {
                            Label("归档", systemImage: "archivebox")
                        }
                        .tint(.blue)
                    }
                    .swipeActions(edge: .leading) {
                        Button {
                            markAsUnread(email)
                        } label: {
                            Label("未读", systemImage: "envelope.badge")
                        }
                        .tint(.gray)
                        
                        Button {
                            flagEmail(email)
                        } label: {
                            Label("标记", systemImage: "flag")
                        }
                        .tint(.orange)
                    }
            }
        }
    }
}

Todo 列表 #

struct TodoListView: View {
    @State private var todos: [Todo] = []
    
    var body: some View {
        List {
            ForEach(todos) { todo in
                TodoRow(todo: todo)
                    .swipeActions(edge: .trailing) {
                        Button(role: .destructive) {
                            deleteTodo(todo)
                        } label: {
                            Label("删除", systemImage: "trash")
                        }
                    }
                    .swipeActions(edge: .leading) {
                        Button {
                            toggleComplete(todo)
                        } label: {
                            Label(
                                todo.isCompleted ? "取消完成" : "完成",
                                systemImage: todo.isCompleted ? "xmark.circle" : "checkmark.circle"
                            )
                        }
                        .tint(todo.isCompleted ? .gray : .green)
                        
                        Button {
                            togglePriority(todo)
                        } label: {
                            Label("优先", systemImage: "star")
                        }
                        .tint(.yellow)
                    }
            }
        }
    }
}

聊天列表 #

struct ChatListView: View {
    @State private var chats: [Chat] = []
    
    var body: some View {
        List {
            ForEach(chats) { chat in
                ChatRow(chat: chat)
                    .swipeActions(edge: .trailing, allowsFullSwipe: false) {
                        Button(role: .destructive) {
                            deleteChat(chat)
                        } label: {
                            Label("删除", systemImage: "trash")
                        }
                        
                        Button {
                            muteChat(chat)
                        } label: {
                            Label(
                                chat.isMuted ? "取消静音" : "静音",
                                systemImage: chat.isMuted ? "speaker.wave.2" : "speaker.slash"
                            )
                        }
                        .tint(.gray)
                    }
                    .swipeActions(edge: .leading) {
                        Button {
                            pinChat(chat)
                        } label: {
                            Label(
                                chat.isPinned ? "取消置顶" : "置顶",
                                systemImage: "pin"
                            )
                        }
                        .tint(.blue)
                    }
            }
        }
    }
}

4. 自定义样式 #

struct CustomSwipeView: View {
    var body: some View {
        List {
            ForEach(items) { item in
                Text(item.title)
                    .swipeActions {
                        // 自定义按钮样式
                        Button {
                            // 操作
                        } label: {
                            Label("自定义", systemImage: "star")
                                .font(.headline)
                                .padding()
                        }
                        .tint(.purple)
                    }
            }
        }
    }
}

5. SwipeActions 文档 #

/// A modifier that configures the swipe actions for a list row.
///
/// Use this modifier to add swipe actions to a list row. The actions appear when
/// the user swipes horizontally across the row.
///
/// - Parameters:
///   - edge: The edge from which the actions appear. Defaults to `.trailing`.
///   - allowsFullSwipe: A Boolean value that determines whether swiping past
///     a threshold automatically triggers the first action. Defaults to `true`.
///   - content: The actions to display when swiping.
@available(iOS 15.0, macOS 12.0, *)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
extension View {
    public func swipeActions<Content>(
        edge: HorizontalEdge = .trailing,
        allowsFullSwipe: Bool = true,
        @ViewBuilder content: () -> Content
    ) -> some View where Content : View
}

参数说明: #

  1. edge

    • .trailing: 从右向左滑动(默认)
    • .leading: 从左向右滑动
  2. allowsFullSwipe

    • true: 允许完整滑动触发第一个操作(默认)
    • false: 禁用完整滑动触发
  3. content

    • 使用 ViewBuilder 构建的滑动操作内容
    • 通常包含一个或多个 Button 视图

注意事项: #

  1. 平台支持

    • iOS 15.0+
    • macOS 12.0+
    • 不支持 tvOS 和 watchOS
  2. 性能考虑

    • 避免在滑动操作中包含复杂的视图层级
    • 保持操作简单直接
  3. 用户体验

    • 最常用的操作应放在最外侧
    • 危险操作应使用 role: .destructive
    • 考虑是否需要允许完整滑动触发
  4. 可访问性

    • 为操作提供清晰的标签
    • 考虑使用适当的图标
  5. 状态管理

    • 确保操作能正确更新视图状态
    • 处理可能的错误情况
本文共 1178 字,上次修改于 Jan 5, 2025