SwiftUI模式

Mattakushi4322026-10-26查看 561复制 200

何时激活:SwiftUI 中的 SwiftUI 视图、布局、状态管理、视图修改器、导航、列表、动画

Download (.md)

📘如何使用这个技能

  1. 1
    复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
  2. 2
    打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
  3. 3
    粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
  4. 4
    直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景

💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。

SKILL.md4610 chars
---
name: swiftui-patterns
description: "When to activate: SwiftUI views, layouts, state management, view modifiers, navigation, lists, animations in SwiftUI"
origin: zakr
metadata:
  namespace: zakr/devtools-pack
  version: 1.0.0
  category: engineering
  language: swift
  platforms: [claude-code, codex, gemini-cli, cursor, aider, windsurf]
---

# SwiftUI Patterns

## State Ownership

Use the right property wrapper for the right scope.

```swift
// @State — private, view-owned mutable state
struct CounterView: View {
    @State private var count = 0
    var body: some View {
        Button("Count: \(count)") { count += 1 }
    }
}

// @Binding — child receives reference to parent state
struct ToggleRow: View {
    let title: String
    @Binding var isOn: Bool
    var body: some View { Toggle(title, isOn: $isOn) }
}

// @StateObject — view creates and owns the ObservableObject
struct ProfileView: View {
    @StateObject private var vm = ProfileViewModel()
    var body: some View { Text(vm.name) }
}

// @ObservedObject — view receives (does NOT own) an ObservableObject
struct OrderRow: View {
    @ObservedObject var order: Order
    var body: some View { Text(order.status) }
}

// @EnvironmentObject — injected from ancestor; app-wide state
struct ThemeButton: View {
    @EnvironmentObject var theme: ThemeStore
    var body: some View { Button("Toggle") { theme.toggle() } }
}
```

## View Decomposition

Break large views into small, focused subviews. Use computed properties for static sub-trees.

```swift
struct ArticleView: View {
    let article: Article

    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 16) {
                headerSection
                AuthorRow(author: article.author)
                Text(article.body).font(.body)
            }
            .padding()
        }
    }

    private var headerSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text(article.title).font(.title.bold())
            Text(article.publishedAt, style: .date).foregroundStyle(.secondary)
        }
    }
}
```

## Navigation (NavigationStack)

Prefer typed `NavigationStack` paths over deprecated `NavigationView`.

```swift
enum Route: Hashable {
    case detail(Item)
    case settings
    case profile(User)
}

struct RootView: View {
    @State private var path: [Route] = []

    var body: some View {
        NavigationStack(path: $path) {
            ItemListView(path: $path)
                .navigationDestination(for: Route.self) { route in
                    switch route {
                    case .detail(let item):  ItemDetailView(item: item)
                    case .settings:          SettingsView()
                    case .profile(let user): ProfileView(user: user)
                    }
                }
        }
    }
}
```

## Lists and Lazy Stacks

```swift
List(items) { item in
    ItemRow(item: item)
        .swipeActions(edge: .trailing) {
            Button("Delete", role: .destructive) { delete(item) }
        }
}
.refreshable { await viewModel.reload() }

ScrollView {
    LazyVStack(spacing: 12, pinnedViews: .sectionHeaders) {
        ForEach(sections) { section in
            Section { ForEach(section.items) { ItemCard(item: $0) } }
                header: { SectionHeader(title: section.title) }
        }
    }
    .padding(.horizontal)
}
```

## Custom View Modifiers

```swift
struct CardStyle: ViewModifier {
    var cornerRadius: CGFloat = 12
    func body(content: Content) -> some View {
        content
            .padding()
            .background(.background, in: RoundedRectangle(cornerRadius: cornerRadius))
            .shadow(color: .black.opacity(0.08), radius: 8, y: 4)
    }
}

extension View {
    func card(cornerRadius: CGFloat = 12) -> some View {
        modifier(CardStyle(cornerRadius: cornerRadius))
    }
}
```

## Animations

```swift
Button("Expand") {
    withAnimation(.spring(response: 0.4, dampingFraction: 0.7)) {
        isExpanded.toggle()
    }
}

// Hero transitions
@Namespace private var heroNamespace
// Source view
Image(item.thumbnail).matchedGeometryEffect(id: item.id, in: heroNamespace)
// Destination view
Image(item.thumbnail).matchedGeometryEffect(id: item.id, in: heroNamespace)
```

## Common Anti-Patterns

- `@State` on reference types — use `@StateObject`
- `@ObservedObject` for view-created objects — they get recreated; use `@StateObject`
- `NavigationView` — deprecated; use `NavigationStack`
- Forcing `AnyView` everywhere — keep views typed with `some View`
- One massive `body` — decompose into subviews
来源:skillsdirectory

评论0

登录后参与评论

还没有评论,来抢沙发吧