[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-1198c0bd-319d-41a1-814d-facd34c94f21":3,"$fmM094faYqqxuBCGAPKbPLt3wjMJ-fOeagdWgUbE3_Zc":43},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":34},"1198c0bd-319d-41a1-814d-facd34c94f21","swiftui-ui-patterns","应用经过验证的SwiftUI UI模式进行导航、表单、异步状态和可重用屏幕。","cat_coding_frontend","mod_coding","sickn33,coding","---\nname: swiftui-ui-patterns\ndescription: Apply proven SwiftUI UI patterns for navigation, sheets, async state, and reusable screens.\nrisk: safe\nsource: \"Dimillian\u002FSkills (MIT)\"\ndate_added: \"2026-03-25\"\n---\n\n# SwiftUI UI Patterns\n\n## Quick start\n\n## When to Use\n- When creating or refactoring SwiftUI screens, flows, or reusable UI components.\n- When you need guidance on navigation, sheets, async state, previews, or component patterns.\n\nChoose a track based on your goal:\n\n### Existing project\n\n- Identify the feature or screen and the primary interaction model (list, detail, editor, settings, tabbed).\n- Find a nearby example in the repo with `rg \"TabView\\(\"` or similar, then read the closest SwiftUI view.\n- Apply local conventions: prefer SwiftUI-native state, keep state local when possible, and use environment injection for shared dependencies.\n- Choose the relevant component reference from `references\u002Fcomponents-index.md` and follow its guidance.\n- If the interaction reveals secondary content by dragging or scrolling the primary content away, read `references\u002Fscroll-reveal.md` before implementing gestures manually.\n- Build the view with small, focused subviews and SwiftUI-native data flow.\n\n### New project scaffolding\n\n- Start with `references\u002Fapp-wiring.md` to wire TabView + NavigationStack + sheets.\n- Add a minimal `AppTab` and `RouterPath` based on the provided skeletons.\n- Choose the next component reference based on the UI you need first (TabView, NavigationStack, Sheets).\n- Expand the route and sheet enums as new screens are added.\n\n## General rules to follow\n\n- Use modern SwiftUI state (`@State`, `@Binding`, `@Observable`, `@Environment`) and avoid unnecessary view models.\n- If the deployment target includes iOS 16 or earlier and cannot use the Observation API introduced in iOS 17, fall back to `ObservableObject` with `@StateObject` for root ownership, `@ObservedObject` for injected observation, and `@EnvironmentObject` only for truly shared app-level state.\n- Prefer composition; keep views small and focused.\n- Use async\u002Fawait with `.task` and explicit loading\u002Ferror states. For restart, cancellation, and debouncing guidance, read `references\u002Fasync-state.md`.\n- Keep shared app services in `@Environment`, but prefer explicit initializer injection for feature-local dependencies and models. For root wiring patterns, read `references\u002Fapp-wiring.md`.\n- Prefer the newest SwiftUI API that fits the deployment target and call out the minimum OS whenever a pattern depends on it.\n- Maintain existing legacy patterns only when editing legacy files.\n- Follow the project's formatter and style guide.\n- **Sheets**: Prefer `.sheet(item:)` over `.sheet(isPresented:)` when state represents a selected model. Avoid `if let` inside a sheet body. Sheets should own their actions and call `dismiss()` internally instead of forwarding `onCancel`\u002F`onConfirm` closures.\n- **Scroll-driven reveals**: Prefer deriving a normalized progress value from scroll offset and driving the visual state from that single source of truth. Avoid parallel gesture state machines unless scroll alone cannot express the interaction.\n\n## State ownership summary\n\nUse the narrowest state tool that matches the ownership model:\n\n| Scenario | Preferred pattern |\n| --- | --- |\n| Local UI state owned by one view | `@State` |\n| Child mutates parent-owned value state | `@Binding` |\n| Root-owned reference model on iOS 17+ | `@State` with an `@Observable` type |\n| Child reads or mutates an injected `@Observable` model on iOS 17+ | Pass it explicitly as a stored property |\n| Shared app service or configuration | `@Environment(Type.self)` |\n| Legacy reference model on iOS 16 and earlier | `@StateObject` at the root, `@ObservedObject` when injected |\n\nChoose the ownership location first, then pick the wrapper. Do not introduce a reference model when plain value state is enough.\n\n## Cross-cutting references\n\n- `references\u002Fnavigationstack.md`: navigation ownership, per-tab history, and enum routing.\n- `references\u002Fsheets.md`: centralized modal presentation and enum-driven sheets.\n- `references\u002Fdeeplinks.md`: URL handling and routing external links into app destinations.\n- `references\u002Fapp-wiring.md`: root dependency graph, environment usage, and app shell wiring.\n- `references\u002Fasync-state.md`: `.task`, `.task(id:)`, cancellation, debouncing, and async UI state.\n- `references\u002Fpreviews.md`: `#Preview`, fixtures, mock environments, and isolated preview setup.\n- `references\u002Fperformance.md`: stable identity, observation scope, lazy containers, and render-cost guardrails.\n\n## Anti-patterns\n\n- Giant views that mix layout, business logic, networking, routing, and formatting in one file.\n- Multiple boolean flags for mutually exclusive sheets, alerts, or navigation destinations.\n- Live service calls directly inside `body`-driven code paths instead of view lifecycle hooks or injected models\u002Fservices.\n- Reaching for `AnyView` to work around type mismatches that should be solved with better composition.\n- Defaulting every shared dependency to `@EnvironmentObject` or a global router without a clear ownership reason.\n\n## Workflow for a new SwiftUI view\n\n1. Define the view's state, ownership location, and minimum OS assumptions before writing UI code.\n2. Identify which dependencies belong in `@Environment` and which should stay as explicit initializer inputs.\n3. Sketch the view hierarchy, routing model, and presentation points; extract repeated parts into subviews. For complex navigation, read `references\u002Fnavigationstack.md`, `references\u002Fsheets.md`, or `references\u002Fdeeplinks.md`. **Build and verify no compiler errors before proceeding.**\n4. Implement async loading with `.task` or `.task(id:)`, plus explicit loading and error states when needed. Read `references\u002Fasync-state.md` when the work depends on changing inputs or cancellation.\n5. Add previews for the primary and secondary states, then add accessibility labels or identifiers when the UI is interactive. Read `references\u002Fpreviews.md` when the view needs fixtures or injected mock dependencies.\n6. Validate with a build: confirm no compiler errors, check that previews render without crashing, ensure state changes propagate correctly, and sanity-check that list identity and observation scope will not cause avoidable re-renders. Read `references\u002Fperformance.md` if the screen is large, scroll-heavy, or frequently updated. For common SwiftUI compilation errors — missing `@State` annotations, ambiguous `ViewBuilder` closures, or mismatched generic types — resolve them before updating callsites. **If the build fails:** read the error message carefully, fix the identified issue, then rebuild before proceeding to the next step. If a preview crashes, isolate the offending subview, confirm its state initialisation is valid, and re-run the preview before continuing.\n\n## Component references\n\nUse `references\u002Fcomponents-index.md` as the entry point. Each component reference should include:\n- Intent and best-fit scenarios.\n- Minimal usage pattern with local conventions.\n- Pitfalls and performance notes.\n- Paths to existing examples in the current repo.\n\n## Adding a new component reference\n\n- Create `references\u002F\u003Ccomponent>.md`.\n- Keep it short and actionable; link to concrete files in the current repo.\n- Update `references\u002Fcomponents-index.md` with the new entry.\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,108,1884,"2026-05-16 13:42:46",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":32,"skillCount":33,"createdAt":26},"前端开发","frontend","mdi-language-html5","HTML\u002FCSS\u002FJavaScript\u002F框架相关",1,96,[35],{"id":36,"skillId":4,"version":37,"fileName":38,"fileSize":39,"filePath":40,"fileHash":41,"manifest":42,"createdAt":19},"9652efda-2e6b-4ca2-98e5-ca92a4722f1b","1.0.0","swiftui-ui-patterns.zip",39438,"uploads\u002Fskills\u002F1198c0bd-319d-41a1-814d-facd34c94f21\u002Fswiftui-ui-patterns.zip","2ca34e610c78724efc108727d2b4356fc535aad44360dda500111d190f7625d6","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":7680},{\"path\":\"agents\u002Fopenai.yaml\",\"isDirectory\":false,\"size\":221},{\"path\":\"references\u002Fapp-wiring.md\",\"isDirectory\":false,\"size\":6637},{\"path\":\"references\u002Fasync-state.md\",\"isDirectory\":false,\"size\":2833},{\"path\":\"references\u002Fcomponents-index.md\",\"isDirectory\":false,\"size\":4303},{\"path\":\"references\u002Fcontrols.md\",\"isDirectory\":false,\"size\":1682},{\"path\":\"references\u002Fdeeplinks.md\",\"isDirectory\":false,\"size\":1703},{\"path\":\"references\u002Ffocus.md\",\"isDirectory\":false,\"size\":2390},{\"path\":\"references\u002Fform.md\",\"isDirectory\":false,\"size\":3062},{\"path\":\"references\u002Fgrids.md\",\"isDirectory\":false,\"size\":1851},{\"path\":\"references\u002Fhaptics.md\",\"isDirectory\":false,\"size\":2049},{\"path\":\"references\u002Finput-toolbar.md\",\"isDirectory\":false,\"size\":1451},{\"path\":\"references\u002Flightweight-clients.md\",\"isDirectory\":false,\"size\":2524},{\"path\":\"references\u002Flist.md\",\"isDirectory\":false,\"size\":2732},{\"path\":\"references\u002Floading-placeholders.md\",\"isDirectory\":false,\"size\":1274},{\"path\":\"references\u002Fmacos-settings.md\",\"isDirectory\":false,\"size\":1997},{\"path\":\"references\u002Fmatched-transitions.md\",\"isDirectory\":false,\"size\":1674},{\"path\":\"references\u002Fmedia.md\",\"isDirectory\":false,\"size\":2040},{\"path\":\"references\u002Fmenu-bar.md\",\"isDirectory\":false,\"size\":2236},{\"path\":\"references\u002Fnavigationstack.md\",\"isDirectory\":false,\"size\":4343},{\"path\":\"references\u002Foverlay.md\",\"isDirectory\":false,\"size\":1238},{\"path\":\"references\u002Fperformance.md\",\"isDirectory\":false,\"size\":1990},{\"path\":\"references\u002Fpreviews.md\",\"isDirectory\":false,\"size\":1688},{\"path\":\"references\u002Fscroll-reveal.md\",\"isDirectory\":false,\"size\":5299},{\"path\":\"references\u002Fscrollview.md\",\"isDirectory\":false,\"size\":2364},{\"path\":\"references\u002Fsearchable.md\",\"isDirectory\":false,\"size\":1727},{\"path\":\"references\u002Fsheets.md\",\"isDirectory\":false,\"size\":4272},{\"path\":\"references\u002Fsplit-views.md\",\"isDirectory\":false,\"size\":2027},{\"path\":\"references\u002Ftabview.md\",\"isDirectory\":false,\"size\":3486},{\"path\":\"references\u002Ftheming.md\",\"isDirectory\":false,\"size\":1776},{\"path\":\"references\u002Ftitle-menus.md\",\"isDirectory\":false,\"size\":2115},{\"path\":\"references\u002Ftop-bar.md\",\"isDirectory\":false,\"size\":1359}]",{"code":44,"message":45,"data":46},200,"success",{"items":47,"stats":48,"page":51},[],{"averageRating":49,"totalRatings":49,"ratingCounts":50},0,[49,49,49,49,49],{"limit":52,"offset":49,"hasMore":53,"nextOffset":52,"ratedOnly":16},15,false]