{"id":"f0ea460d-54c8-441f-bf4d-b4608fe202a3","shortId":"ZVvmvZ","kind":"skill","title":"Swiftui Layout Components","tagline":"Swift Ios Skills skill by Dpearson2699","description":"# SwiftUI Layout & Components\n\nLayout and component patterns for SwiftUI apps targeting iOS 26+ with Swift 6.3. Covers stack and grid layouts, list patterns, scroll views, forms, controls, search, and overlays. Patterns are backward-compatible to iOS 17 unless noted.\n\n## Contents\n\n- [Layout Fundamentals](#layout-fundamentals)\n- [Grid Layouts](#grid-layouts)\n- [List Patterns](#list-patterns)\n- [ScrollView](#scrollview)\n- [Form and Controls](#form-and-controls)\n- [Searchable](#searchable)\n- [Overlay and Presentation](#overlay-and-presentation)\n- [Common Mistakes](#common-mistakes)\n- [Review Checklist](#review-checklist)\n- [References](#references)\n\n## Layout Fundamentals\n\n### Standard Stacks\n\nUse `VStack`, `HStack`, and `ZStack` for small, fixed-size content. They render all children immediately.\n\n```swift\nVStack(alignment: .leading, spacing: 8) {\n    Text(title).font(.headline)\n    Text(subtitle).font(.subheadline).foregroundStyle(.secondary)\n}\n```\n\n### Lazy Stacks\n\nUse `LazyVStack` and `LazyHStack` inside `ScrollView` for large or dynamic collections. They create child views on demand as they scroll into view.\n\n```swift\nScrollView {\n    LazyVStack(spacing: 12) {\n        ForEach(items) { item in\n            ItemRow(item: item)\n        }\n    }\n    .padding(.horizontal)\n}\n```\n\n**When to use which:**\n- **Non-lazy stacks:** Small, fixed content (headers, toolbars, forms with few fields)\n- **Lazy stacks:** Large or unknown-size collections, feeds, chat messages\n\n## Grid Layouts\n\nUse `LazyVGrid` for icon pickers, media galleries, and dense visual selections. Use `.adaptive` columns for layouts that scale across device sizes, or `.flexible` columns for a fixed column count.\n\n```swift\n// Adaptive grid -- columns adjust to fit\nlet columns = [GridItem(.adaptive(minimum: 120, maximum: 1024))]\n\nLazyVGrid(columns: columns, spacing: 6) {\n    ForEach(items) { item in\n        ThumbnailView(item: item)\n            .aspectRatio(1, contentMode: .fit)\n    }\n}\n```\n\n```swift\n// Fixed 3-column grid\nlet columns = Array(repeating: GridItem(.flexible(minimum: 100), spacing: 4), count: 3)\n\nLazyVGrid(columns: columns, spacing: 4) {\n    ForEach(items) { item in\n        ThumbnailView(item: item)\n    }\n}\n```\n\nUse `.aspectRatio` for cell sizing. Never place `GeometryReader` inside lazy containers -- it forces eager measurement and defeats lazy loading. Use `.onGeometryChange` (iOS 18+) if you need to read dimensions.\n\nSee [references/grids.md](references/grids.md) for full grid patterns and design choices.\n\n## List Patterns\n\nUse `List` for feed-style content and settings rows where built-in row reuse, selection, and accessibility matter.\n\n```swift\nList {\n    Section(\"General\") {\n        NavigationLink(\"Display\") { DisplaySettingsView() }\n        NavigationLink(\"Haptics\") { HapticsSettingsView() }\n    }\n    Section(\"Account\") {\n        Button(\"Sign Out\", role: .destructive) { }\n    }\n}\n.listStyle(.insetGrouped)\n```\n\n**Key patterns:**\n- `.listStyle(.plain)` for feed layouts, `.insetGrouped` for settings\n- `.scrollContentBackground(.hidden)` + custom background for themed surfaces\n- `.listRowInsets(...)` and `.listRowSeparator(.hidden)` for spacing and separator control\n- Pair with `ScrollViewReader` for scroll-to-top or jump-to-id\n- Use `.refreshable { }` for pull-to-refresh feeds\n- Use `.contentShape(Rectangle())` on rows that should be tappable end-to-end\n\n**iOS 26:** Apply `.scrollEdgeEffectStyle(.soft, for: .top)` for modern scroll edge effects.\n\nSee [references/list.md](references/list.md) for full list patterns including feed lists with scroll-to-top.\n\n## ScrollView\n\nUse `ScrollView` with lazy stacks when you need custom layout, mixed content, or horizontal scrolling.\n\n```swift\nScrollView(.horizontal, showsIndicators: false) {\n    LazyHStack(spacing: 8) {\n        ForEach(chips) { chip in\n            ChipView(chip: chip)\n        }\n    }\n}\n```\n\n**ScrollViewReader:** Enables programmatic scrolling to specific items.\n\n```swift\nScrollViewReader { proxy in\n    ScrollView {\n        LazyVStack {\n            ForEach(messages) { message in\n                MessageRow(message: message).id(message.id)\n            }\n        }\n    }\n    .onChange(of: messages.last?.id) { _, newValue in\n        if let id = newValue {\n            withAnimation { proxy.scrollTo(id, anchor: .bottom) }\n        }\n    }\n}\n```\n\n**`safeAreaInset(edge:)`** pins content (input bars, toolbars) above the keyboard without affecting scroll layout.\n\n**iOS 26 additions:**\n- `.scrollEdgeEffectStyle(.soft, for: .top)` -- fading edge effect\n- `.backgroundExtensionEffect()` -- mirror/blur at safe area edges (use sparingly, one per screen)\n- `.safeAreaBar(edge:)` -- attach bar views that integrate with scroll effects\n\nSee [references/scrollview.md](references/scrollview.md) for full scroll patterns and iOS 26 edge effects.\n\n## Form and Controls\n\n### Form\n\nUse `Form` for structured settings and input screens. Group related controls into `Section` blocks.\n\n```swift\nForm {\n    Section(\"Notifications\") {\n        Toggle(\"Mentions\", isOn: $prefs.mentions)\n        Toggle(\"Follows\", isOn: $prefs.follows)\n    }\n    Section(\"Appearance\") {\n        Picker(\"Theme\", selection: $theme) {\n            ForEach(Theme.allCases, id: \\.self) { Text($0.title).tag($0) }\n        }\n        Slider(value: $fontScale, in: 0.5...1.5, step: 0.1)\n    }\n}\n.formStyle(.grouped)\n.scrollContentBackground(.hidden)\n```\n\nUse `@FocusState` to manage keyboard focus in input-heavy forms. Wrap in `NavigationStack` only when presented standalone or in a sheet.\n\n### Controls\n\n| Control | Usage |\n|---------|-------|\n| `Toggle` | Boolean preferences |\n| `Picker` | Discrete choices; `.segmented` for 2-4 options |\n| `Slider` | Numeric ranges with visible value label |\n| `DatePicker` | Date/time selection |\n| `TextField` | Text input with `.keyboardType`, `.textInputAutocapitalization` |\n\nBind controls directly to `@State`, `@Binding`, or `@AppStorage`. Group related controls in `Form` sections. Use `.disabled(...)` to reflect locked or inherited settings. Use `Label` inside toggles to combine icon + text when it adds clarity.\n\n```swift\n// Toggle sections\nForm {\n  Section(\"Notifications\") {\n    Toggle(\"Mentions\", isOn: $preferences.notificationsMentionsEnabled)\n    Toggle(\"Follows\", isOn: $preferences.notificationsFollowsEnabled)\n  }\n}\n\n// Slider with value text\nSection(\"Font Size\") {\n  Slider(value: $fontSizeScale, in: 0.5...1.5, step: 0.1)\n  Text(\"Scale: \\(String(format: \"%.1f\", fontSizeScale))\")\n}\n\n// Picker for enums\nPicker(\"Default Visibility\", selection: $visibility) {\n  ForEach(Visibility.allCases, id: \\.self) { option in\n    Text(option.title).tag(option)\n  }\n}\n```\n\nAvoid `.pickerStyle(.segmented)` for large sets; use menu or inline styles. Don't hide labels for sliders; always show context.\n\nSee [references/form.md](references/form.md) for full form examples.\n\n## Searchable\n\nAdd native search UI with `.searchable`. Use `.searchScopes` for multiple modes and `.task(id:)` for debounced async results.\n\n```swift\n@MainActor\nstruct ExploreView: View {\n  @State private var searchQuery = \"\"\n  @State private var searchScope: SearchScope = .all\n  @State private var isSearching = false\n  @State private var results: [SearchResult] = []\n\n  var body: some View {\n    List {\n      if isSearching {\n        ProgressView()\n      } else {\n        ForEach(results) { result in\n          SearchRow(result: result)\n        }\n      }\n    }\n    .searchable(\n      text: $searchQuery,\n      placement: .navigationBarDrawer(displayMode: .always),\n      prompt: Text(\"Search\")\n    )\n    .searchScopes($searchScope) {\n      ForEach(SearchScope.allCases, id: \\.self) { scope in\n        Text(scope.title)\n      }\n    }\n    .task(id: searchQuery) {\n      await runSearch()\n    }\n  }\n\n  private func runSearch() async {\n    guard !searchQuery.isEmpty else {\n      results = []\n      return\n    }\n    isSearching = true\n    defer { isSearching = false }\n    try? await Task.sleep(for: .milliseconds(250))\n    results = await fetchResults(query: searchQuery, scope: searchScope)\n  }\n}\n```\n\nShow a placeholder when search is empty. Debounce input to avoid overfetching. Keep search state local to the view. Avoid running searches for empty strings.\n\n## Overlay and Presentation\n\nUse `.overlay(alignment:)` for transient UI (toasts, banners) without affecting layout.\n\n```swift\nstruct AppRootView: View {\n  @State private var toast: Toast?\n\n  var body: some View {\n    content\n      .overlay(alignment: .top) {\n        if let toast {\n          ToastView(toast: toast)\n            .transition(.move(edge: .top).combined(with: .opacity))\n            .onAppear {\n              Task {\n                try? await Task.sleep(for: .seconds(2))\n                withAnimation { self.toast = nil }\n              }\n            }\n        }\n      }\n  }\n}\n```\n\nPrefer overlays for transient UI rather than embedding in layout stacks. Use transitions and short auto-dismiss timers. Keep overlays aligned to a clear edge (`.top` or `.bottom`). Avoid overlays that block all interaction unless explicitly needed. Don't stack many overlays; use a queue or replace the current toast.\n\n**fullScreenCover:** Use `.fullScreenCover(item:)` for immersive presentations that cover the entire screen (media viewers, onboarding flows).\n\n## Common Mistakes\n\n1. Using non-lazy stacks for large collections -- causes all children to render immediately\n2. Placing `GeometryReader` inside lazy containers -- defeats lazy loading\n3. Using array indices as `ForEach` IDs -- causes incorrect diffing and UI bugs\n4. Nesting scroll views of the same axis -- causes gesture conflicts\n5. Heavy custom layouts inside `List` rows -- use `ScrollView` + `LazyVStack` instead\n6. Missing `.contentShape(Rectangle())` on tappable rows -- tap area is text-only\n7. Hard-coding frame dimensions for sheets -- use `.presentationSizing` instead\n8. Running searches on empty strings -- always guard against empty queries\n9. Mixing `List` and `ScrollView` in the same hierarchy -- gesture conflicts\n10. Using `.pickerStyle(.segmented)` for large option sets -- use menu or inline styles\n\n## Review Checklist\n\n- [ ] `LazyVStack`/`LazyHStack` used for large or dynamic collections\n- [ ] Stable `Identifiable` IDs on all `ForEach` items (not array indices)\n- [ ] No `GeometryReader` inside lazy containers\n- [ ] `List` style matches context (`.plain` for feeds, `.insetGrouped` for settings)\n- [ ] `Form` used for structured input screens (not custom stacks)\n- [ ] `.searchable` debounces input with `.task(id:)`\n- [ ] `.refreshable` added where data source supports pull-to-refresh\n- [ ] Overlays use transitions and auto-dismiss timers\n- [ ] `.contentShape(Rectangle())` on tappable rows\n- [ ] `@FocusState` manages keyboard focus in forms\n\n## References\n\n- Grid patterns: [references/grids.md](references/grids.md)\n- List and section patterns: [references/list.md](references/list.md)\n- ScrollView and lazy stacks: [references/scrollview.md](references/scrollview.md)\n- Form patterns: [references/form.md](references/form.md)\n- Architecture and state management: see `swiftui-patterns` skill\n- Navigation patterns: see `swiftui-navigation` skill","tags":["swiftui","layout","components","swift","ios","skills","dpearson2699"],"capabilities":["skill","source-dpearson2699","category-swift-ios-skills"],"categories":["swift-ios-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/dpearson2699/swift-ios-skills/swiftui-layout-components","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"install_from":"skills.sh"}},"qualityScore":"0.300","qualityRationale":"deterministic score 0.30 from registry signals: · indexed on skills.sh · published under dpearson2699/swift-ios-skills","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T05:40:38.650Z","embedding":null,"createdAt":"2026-04-18T20:33:50.985Z","updatedAt":"2026-04-22T05:40:38.650Z","lastSeenAt":"2026-04-22T05:40:38.650Z","tsv":"'-4':671 '0':624 '0.1':632,751 '0.5':629,748 '0.title':622 '1':257,1064 '1.5':630,749 '10':1169 '100':272 '1024':243 '12':160 '120':241 '17':47 '18':311 '1f':756 '2':670,991,1079 '250':907 '26':22,430,539,578 '3':262,276,1088 '4':274,281,1101 '5':1112 '6':248,1123 '6.3':25 '7':1136 '8':121,479,1147 '9':1158 'access':348 'account':361 'across':218 'ad':1233 'adapt':212,230,239 'add':721,804 'addit':540 'adjust':233 'affect':535,952 'align':118,945,969,1016 'alway':793,869,1153 'anchor':522 'app':19 'appear':612 'appli':431 'approotview':956 'appstorag':696 'architectur':1282 'area':552,1131 'array':267,1090,1200 'aspectratio':256,290 'async':820,891 'attach':561 'auto':1011,1247 'auto-dismiss':1010,1246 'avoid':776,925,934,1024 'await':886,903,909,987 'axi':1108 'background':382 'backgroundextensioneffect':548 'backward':43 'backward-compat':42 'banner':950 'bar':529,562 'bind':689,694 'block':598,1027 'bodi':848,964 'boolean':663 'bottom':523,1023 'bug':1100 'built':342 'built-in':341 'button':362 'category-swift-ios-skills' 'caus':1073,1095,1109 'cell':292 'chat':196 'checklist':90,93,1183 'child':147 'children':114,1075 'chip':481,482,485,486 'chipview':484 'choic':327,667 'clariti':722 'clear':1019 'code':1139 'collect':144,194,1072,1191 'column':213,223,227,232,237,245,246,263,266,278,279 'combin':716,981 'common':84,87,1062 'common-mistak':86 'compat':44 'compon':3,12,15 'conflict':1111,1168 'contain':299,1084,1206 'content':50,110,180,336,468,527,967 'contentmod':258 'contentshap':417,1125,1250 'context':795,1210 'control':36,70,74,394,583,595,659,660,690,699 'count':228,275 'cover':26,1054 'creat':146 'current':1044 'custom':381,465,1114,1224 'data':1235 'date/time':681 'datepick':680 'debounc':819,922,1227 'default':762 'defeat':305,1085 'defer':899 'demand':150 'dens':208 'design':326 'destruct':366 'devic':219 'dif':1097 'dimens':317,1141 'direct':691 'disabl':704 'discret':666 'dismiss':1012,1248 'display':355 'displaymod':868 'displaysettingsview':356 'dpearson2699':9 'dynam':143,1190 'eager':302 'edg':439,525,546,553,560,579,979,1020 'effect':440,547,568,580 'els':855,894 'embed':1002 'empti':921,938,1151,1156 'enabl':488 'end':426,428 'end-to-end':425 'entir':1056 'enum':760 'exampl':802 'explicit':1031 'exploreview':825 'fade':545 'fals':476,841,901 'feed':195,334,374,415,449,1213 'feed-styl':333 'fetchresult':910 'field':186 'fit':235,259 'fix':108,179,226,261 'fixed-s':107 'flexibl':222,270 'flow':1061 'focus':642,1258 'focusst':638,1255 'follow':608,734 'font':124,128,742 'fontscal':627 'fontsizescal':746,757 'forc':301 'foreach':161,249,282,480,500,617,766,856,875,1093,1197 'foregroundstyl':130 'form':35,68,72,183,581,584,586,600,647,701,726,801,1217,1260,1278 'form-and-control':71 'format':755 'formstyl':633 'frame':1140 'full':322,445,573,800 'fullscreencov':1046,1048 'func':889 'fundament':52,55,97 'galleri':206 'general':353 'geometryread':296,1081,1203 'gestur':1110,1167 'grid':29,56,59,198,231,264,323,1262 'grid-layout':58 'griditem':238,269 'group':593,634,697 'guard':892,1154 'haptic':358 'hapticssettingsview':359 'hard':1138 'hard-cod':1137 'header':181 'headlin':125 'heavi':646,1113 'hidden':380,389,636 'hide':789 'hierarchi':1166 'horizont':169,470,474 'hstack':102 'icon':203,717 'id':407,507,512,517,521,619,768,817,877,884,1094,1194,1231 'identifi':1193 'immedi':115,1078 'immers':1051 'includ':448 'incorrect':1096 'indic':1091,1201 'inherit':709 'inlin':785,1180 'input':528,591,645,685,923,1221,1228 'input-heavi':644 'insetgroup':368,376,1214 'insid':138,297,713,1082,1116,1204 'instead':1122,1146 'integr':565 'interact':1029 'io':5,21,46,310,429,538,577 'ison':605,609,731,735 'issearch':840,853,897,900 'item':162,163,166,167,250,251,254,255,283,284,287,288,493,1049,1198 'itemrow':165 'jump':405 'jump-to-id':404 'keep':927,1014 'key':369 'keyboard':533,641,1257 'keyboardtyp':687 'label':679,712,790 'larg':141,189,780,1071,1174,1188 'layout':2,11,13,30,51,54,57,60,96,199,215,375,466,537,953,1004,1115 'layout-fundament':53 'lazi':132,176,187,298,306,460,1068,1083,1086,1205,1274 'lazyhstack':137,477,1185 'lazyvgrid':201,244,277 'lazyvstack':135,158,499,1121,1184 'lead':119 'let':236,265,516,972 'list':31,61,64,328,331,351,446,450,851,1117,1160,1207,1266 'list-pattern':63 'listrowinset':386 'listrowsepar':388 'liststyl':367,371 'load':307,1087 'local':930 'lock':707 'mainactor':823 'manag':640,1256,1285 'mani':1036 'match':1209 'matter':349 'maximum':242 'measur':303 'media':205,1058 'mention':604,730 'menu':783,1178 'messag':197,501,502,505,506 'message.id':508 'messagerow':504 'messages.last':511 'millisecond':906 'minimum':240,271 'mirror/blur':549 'miss':1124 'mistak':85,88,1063 'mix':467,1159 'mode':814 'modern':437 'move':978 'multipl':813 'nativ':805 'navig':1291,1296 'navigationbardraw':867 'navigationlink':354,357 'navigationstack':650 'need':314,464,1032 'nest':1102 'never':294 'newvalu':513,518 'nil':994 'non':175,1067 'non-lazi':174,1066 'note':49 'notif':602,728 'numer':674 'onappear':984 'onboard':1060 'onchang':509 'one':556 'ongeometrychang':309 'opac':983 'option':672,770,775,1175 'option.title':773 'overfetch':926 'overlay':39,77,81,940,944,968,996,1015,1025,1037,1242 'overlay-and-present':80 'pad':168 'pair':395 'pattern':16,32,40,62,65,324,329,370,447,575,1263,1269,1279,1289,1292 'per':557 'picker':204,613,665,758,761 'pickerstyl':777,1171 'pin':526 'place':295,1080 'placehold':917 'placement':866 'plain':372,1211 'prefer':664,995 'preferences.notificationsfollowsenabled':736 'preferences.notificationsmentionsenabled':732 'prefs.follows':610 'prefs.mentions':606 'present':79,83,653,942,1052 'presentations':1145 'privat':828,832,838,843,888,959 'programmat':489 'progressview':854 'prompt':870 'proxi':496 'proxy.scrollto':520 'pull':412,1239 'pull-to-refresh':411,1238 'queri':911,1157 'queue':1040 'rang':675 'rather':1000 'read':316 'rectangl':418,1126,1251 'refer':94,95,1261 'references/form.md':797,798,1280,1281 'references/grids.md':319,320,1264,1265 'references/list.md':442,443,1270,1271 'references/scrollview.md':570,571,1276,1277 'reflect':706 'refresh':409,414,1232,1241 'relat':594,698 'render':112,1077 'repeat':268 'replac':1042 'result':821,845,857,858,861,862,895,908 'return':896 'reus':345 'review':89,92,1182 'review-checklist':91 'role':365 'row':339,344,420,1118,1129,1254 'run':935,1148 'runsearch':887,890 'safe':551 'safeareabar':559 'safeareainset':524 'scale':217,753 'scope':879,913 'scope.title':882 'screen':558,592,1057,1222 'scroll':33,153,400,438,453,471,490,536,567,574,1103 'scroll-to-top':399,452 'scrollcontentbackground':379,635 'scrolledgeeffectstyl':432,541 'scrollview':66,67,139,157,456,458,473,498,1120,1162,1272 'scrollviewread':397,487,495 'search':37,806,872,919,928,936,1149 'searchabl':75,76,803,809,863,1226 'searchqueri':830,865,885,912 'searchquery.isempty':893 'searchresult':846 'searchrow':860 'searchscop':811,834,835,873,874,914 'searchscope.allcases':876 'second':990 'secondari':131 'section':352,360,597,601,611,702,725,727,741,1268 'see':318,441,569,796,1286,1293 'segment':668,778,1172 'select':210,346,615,682,764 'self':620,769,878 'self.toast':993 'separ':393 'set':338,378,589,710,781,1176,1216 'sheet':658,1143 'short':1009 'show':794,915 'showsind':475 'sign':363 'size':109,193,220,293,743 'skill':6,7,1290,1297 'slider':625,673,737,744,792 'small':106,178 'soft':433,542 'sourc':1236 'source-dpearson2699' 'space':120,159,247,273,280,391,478 'spare':555 'specif':492 'stabl':1192 'stack':27,99,133,177,188,461,1005,1035,1069,1225,1275 'standalon':654 'standard':98 'state':693,827,831,837,842,929,958,1284 'step':631,750 'string':754,939,1152 'struct':824,955 'structur':588,1220 'style':335,786,1181,1208 'subheadlin':129 'subtitl':127 'support':1237 'surfac':385 'swift':4,24,116,156,229,260,350,472,494,599,723,822,954 'swiftui':1,10,18,1288,1295 'swiftui-navig':1294 'swiftui-pattern':1287 'tag':623,774 'tap':1130 'tappabl':424,1128,1253 'target':20 'task':816,883,985,1230 'task.sleep':904,988 'text':122,126,621,684,718,740,752,772,864,871,881,1134 'text-on':1133 'textfield':683 'textinputautocapit':688 'theme':384,614,616 'theme.allcases':618 'thumbnailview':253,286 'timer':1013,1249 'titl':123 'toast':949,961,962,973,975,976,1045 'toastview':974 'toggl':603,607,662,714,724,729,733 'toolbar':182,530 'top':402,435,455,544,970,980,1021 'transient':947,998 'transit':977,1007,1244 'tri':902,986 'true':898 'ui':807,948,999,1099 'unknown':192 'unknown-s':191 'unless':48,1030 'usag':661 'use':100,134,172,200,211,289,308,330,408,416,457,554,585,637,703,711,782,810,943,1006,1038,1047,1065,1089,1119,1144,1170,1177,1186,1218,1243 'valu':626,678,739,745 'var':829,833,839,844,847,960,963 'view':34,148,155,563,826,850,933,957,966,1104 'viewer':1059 'visibility.allcases':767 'visibl':677,763,765 'visual':209 'vstack':101,117 'withanim':519,992 'without':534,951 'wrap':648 'zstack':104","prices":[{"id":"faaa9250-28c3-4a4b-a3ff-8ae1c38e4b48","listingId":"f0ea460d-54c8-441f-bf4d-b4608fe202a3","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"dpearson2699","category":"swift-ios-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T20:33:50.985Z"}],"sources":[{"listingId":"f0ea460d-54c8-441f-bf4d-b4608fe202a3","source":"github","sourceId":"dpearson2699/swift-ios-skills/swiftui-layout-components","sourceUrl":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/swiftui-layout-components","isPrimary":false,"firstSeenAt":"2026-04-18T22:01:24.641Z","lastSeenAt":"2026-04-22T00:53:45.329Z"},{"listingId":"f0ea460d-54c8-441f-bf4d-b4608fe202a3","source":"skills_sh","sourceId":"dpearson2699/swift-ios-skills/swiftui-layout-components","sourceUrl":"https://skills.sh/dpearson2699/swift-ios-skills/swiftui-layout-components","isPrimary":true,"firstSeenAt":"2026-04-18T20:33:50.985Z","lastSeenAt":"2026-04-22T05:40:38.650Z"}],"details":{"listingId":"f0ea460d-54c8-441f-bf4d-b4608fe202a3","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"dpearson2699","slug":"swiftui-layout-components","source":"skills_sh","category":"swift-ios-skills","skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/swiftui-layout-components"},"updatedAt":"2026-04-22T05:40:38.650Z"}}