@mmerterden/multi-agent-pipeline 20.17.1 → 20.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/docs/facts.json +6 -6
- package/install/catalog-history.json +1 -1
- package/manifest.json +75 -37
- package/package.json +1 -1
- package/pipeline/skills/.skill-manifest.json +33 -13
- package/pipeline/skills/.skills-index.json +66 -11
- package/pipeline/skills/shared/README.md +18 -13
- package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +3 -1
- package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +2 -1
- package/pipeline/skills/shared/external/hig-app-icons/SKILL.md +159 -0
- package/pipeline/skills/shared/external/hig-app-icons/evals/evals.json +48 -0
- package/pipeline/skills/shared/external/hig-app-icons/evals/trigger-eval.json +22 -0
- package/pipeline/skills/shared/external/hig-app-icons/references/icon-workflow.md +115 -0
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +32 -4
- package/pipeline/skills/shared/external/hig-components-layout/evals/evals.json +47 -0
- package/pipeline/skills/shared/external/hig-components-layout/evals/trigger-eval.json +22 -0
- package/pipeline/skills/shared/external/hig-components-layout/references/bars-and-tabs.md +231 -0
- package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +5 -30
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +1 -1
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +23 -4
- package/pipeline/skills/shared/external/hig-foundations/evals/evals.json +47 -0
- package/pipeline/skills/shared/external/hig-foundations/evals/trigger-eval.json +21 -0
- package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +34 -26
- package/pipeline/skills/shared/external/hig-foundations/references/type-color-spacing.md +219 -0
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +5 -4
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +19 -3
- package/pipeline/skills/shared/external/hig-patterns/references/onboarding-and-states.md +188 -0
- package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +5 -11
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +17 -5
- package/pipeline/skills/shared/external/hig-platforms/references/ipad-layout.md +218 -0
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +4 -1
- package/pipeline/skills/shared/external/ios-accessibility/references/large-content-and-appearance.md +135 -0
- package/pipeline/skills/shared/external/ios-design-review/SKILL.md +146 -0
- package/pipeline/skills/shared/external/ios-design-review/evals/evals.json +48 -0
- package/pipeline/skills/shared/external/ios-design-review/evals/trigger-eval.json +22 -0
- package/pipeline/skills/shared/external/ios-design-review/references/appearance-matrix.md +135 -0
- package/pipeline/skills/shared/external/ios-design-review/references/checklist.md +193 -0
- package/pipeline/skills/shared/external/ios-haptics/SKILL.md +191 -0
- package/pipeline/skills/shared/external/ios-haptics/evals/evals.json +49 -0
- package/pipeline/skills/shared/external/ios-haptics/evals/trigger-eval.json +22 -0
- package/pipeline/skills/shared/external/ios-haptics/references/core-haptics.md +215 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/NOTICE.md +53 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/SKILL.md +170 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/evals/evals.json +50 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/evals/trigger-eval.json +22 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/references/api-map.md +212 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/references/fixed-assumptions.md +145 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/references/poses-and-panes.md +122 -0
- package/pipeline/skills/shared/external/ios-sf-symbols/SKILL.md +177 -0
- package/pipeline/skills/shared/external/ios-sf-symbols/evals/evals.json +49 -0
- package/pipeline/skills/shared/external/ios-sf-symbols/evals/trigger-eval.json +22 -0
- package/pipeline/skills/shared/external/ios-sf-symbols/references/effects-and-custom-symbols.md +135 -0
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +38 -50
- package/pipeline/skills/shared/external/swiftui-animation/evals/evals.json +47 -0
- package/pipeline/skills/shared/external/swiftui-animation/evals/trigger-eval.json +22 -0
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +7 -73
- package/pipeline/skills/shared/external/swiftui-animation/references/scroll-effects.md +185 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +6 -6
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-advanced.md +3 -253
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-basics.md +4 -47
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-transitions.md +3 -111
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/liquid-glass.md +11 -381
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +184 -224
- package/pipeline/skills/shared/external/swiftui-liquid-glass/evals/evals.json +47 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/evals/trigger-eval.json +22 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +246 -33
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/uikit-glass.md +227 -0
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +15 -18
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/components-index.md +1 -1
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/haptics.md +6 -68
- package/pipeline/skills/skills-index.md +16 -11
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +0 -786
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# iPhone Duo API map
|
|
2
|
+
|
|
3
|
+
Every API this skill relies on, grouped by job, with the iOS version that
|
|
4
|
+
introduced it. *(27.1 beta)* marks symbols documented as beta in the iOS 27.1
|
|
5
|
+
SDK; their names and behaviour may change before release.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
1. Size, screen and shape
|
|
10
|
+
2. Reserved regions
|
|
11
|
+
3. Arrangements
|
|
12
|
+
4. Vertical bars
|
|
13
|
+
5. Sheets
|
|
14
|
+
6. Hinge
|
|
15
|
+
7. Scenes and accessories
|
|
16
|
+
|
|
17
|
+
## 1. Size, screen and shape
|
|
18
|
+
|
|
19
|
+
| Job | SwiftUI | UIKit | iOS |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| Size class | `horizontalSizeClass`, `verticalSizeClass` environment | trait collection size classes | 13 |
|
|
22
|
+
| Space actually available | `GeometryReader`, `onGeometryChange(for:of:action:)` | `view.bounds`, `viewDidLayoutSubviews`, `layoutSubviews` | 13 / 16 |
|
|
23
|
+
| Display scale | `displayScale` environment | `traitCollection.displayScale` | 13 / 8 |
|
|
24
|
+
| A window for a scene | | `UIWindow(windowScene:)` | 13 |
|
|
25
|
+
| The scene's screen, if truly needed | | `view.window?.windowScene?.screen` | 13 |
|
|
26
|
+
| Choose among layouts | `ViewThatFits`, `AnyLayout` | | 16 |
|
|
27
|
+
| Size relative to container | `containerRelativeFrame(_:alignment:)` | Auto Layout | 17 |
|
|
28
|
+
| Corners concentric with the device | `ConcentricRectangle` | `UICornerConfiguration`, `UIView.cornerConfiguration` | 26 |
|
|
29
|
+
|
|
30
|
+
`UIScreen.main` is deprecated as of iOS 26. Apple's guidance is to base layout
|
|
31
|
+
on the scene or containing view's bounds and on size classes, and not to use
|
|
32
|
+
`userInterfaceIdiom` or `UIInterfaceOrientation` for layout decisions.
|
|
33
|
+
|
|
34
|
+
## 2. Reserved regions
|
|
35
|
+
|
|
36
|
+
| Job | SwiftUI | UIKit |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Region type | `ReservedRegion` *(27.1 beta)* | `UIView.ReservedRegion` *(27.1 beta)* |
|
|
39
|
+
| Query | `GeometryProxy.reservedRegions(kind:options:layoutDirectionBehavior:)` *(27.1 beta)* | `UIView.reservedRegions(kind:options:)` *(27.1 beta)* |
|
|
40
|
+
| Kinds | `.division` (fold), `.occlusion` (cameras) | same |
|
|
41
|
+
| Options | `.includeInactive` | same |
|
|
42
|
+
| Properties | `frame` (includes margins), `margins`, `isActive`, `kind`, `id` | `frame`, `margins`, `isActive`, `kind` (no `id`) |
|
|
43
|
+
|
|
44
|
+
```swift
|
|
45
|
+
struct FoldAwareGrid<Content: View>: View {
|
|
46
|
+
@ViewBuilder var content: (_ columns: Int) -> Content
|
|
47
|
+
|
|
48
|
+
var body: some View {
|
|
49
|
+
GeometryReader { proxy in
|
|
50
|
+
let hasFold = !proxy.reservedRegions(kind: .division, options: .includeInactive).isEmpty
|
|
51
|
+
let base = proxy.size.width > proxy.size.height ? 3 : 2
|
|
52
|
+
content(hasFold && base.isMultiple(of: 2) == false ? base + 1 : base)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Notes:
|
|
59
|
+
|
|
60
|
+
- The query returns regions that intersect the view whether active or not.
|
|
61
|
+
Filter `isActive` when positioning for the current pose.
|
|
62
|
+
- `frame` already contains `margins`, the clearance kept for interactive
|
|
63
|
+
content. Avoiding `frame` is enough for controls; inset `frame` by
|
|
64
|
+
`margins` when full-bleed media may run up to the bare hardware area.
|
|
65
|
+
- SwiftUI mirrors region frames for right-to-left by default
|
|
66
|
+
(`layoutDirectionBehavior: .mirrors`), so a custom `Layout` can compare them
|
|
67
|
+
with subview frames directly. Pass `.fixed` for the physical frames.
|
|
68
|
+
- System containers (split views, lists, scroll views, sheets, alerts, menus)
|
|
69
|
+
already avoid reserved regions; custom views and custom layouts are the
|
|
70
|
+
ones that need this API.
|
|
71
|
+
|
|
72
|
+
## 3. Arrangements
|
|
73
|
+
|
|
74
|
+
| Job | SwiftUI | UIKit |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| Container | `ArrangementView(primary:secondary:)` *(27.1 beta)* | `UIArrangementViewController` *(27.1 beta)* |
|
|
77
|
+
| Choose style | `.arrangementViewStyle(.split)` / `.overlay` / `.automatic` | `updateArrangement(_:animated:)` with `UISplitArrangement` / `UIOverlayArrangement` |
|
|
78
|
+
| Limit axes | `.split.axes(.vertical)`, `.overlay.axes(...)` | `axes(_:)` on the arrangement |
|
|
79
|
+
| Assign content | the two view builders | `setViewController(_:for:animated:)` with `.primary` / `.secondary` |
|
|
80
|
+
| Split sizing | `splitArrangementLayoutRatio(_:)`, `splitArrangementLayoutSize(...)`, `splitArrangementFixedLayoutSize(...)` | `UISplitArrangement.Dimension` |
|
|
81
|
+
| Overlay details | `overlayArrangementEdge(_:)`, `overlayArrangementZIndex` environment | `state(for:)` |
|
|
82
|
+
|
|
83
|
+
```swift
|
|
84
|
+
ArrangementView {
|
|
85
|
+
NowPlayingView()
|
|
86
|
+
} secondary: {
|
|
87
|
+
LyricsView()
|
|
88
|
+
}
|
|
89
|
+
.arrangementViewStyle(.split)
|
|
90
|
+
|
|
91
|
+
ArrangementView {
|
|
92
|
+
PlayerControls()
|
|
93
|
+
} secondary: {
|
|
94
|
+
VideoSurface()
|
|
95
|
+
}
|
|
96
|
+
.arrangementViewStyle(.overlay)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The automatic style resolves to split. Split goes side by side when wider than
|
|
100
|
+
tall and stacks when taller than wide; overlay layers primary over secondary
|
|
101
|
+
when closed or fully open and places them on either side of the fold when
|
|
102
|
+
partially open (primary trailing or bottom, secondary leading or top).
|
|
103
|
+
|
|
104
|
+
Placement rules: navigation containers go around an arrangement, never inside
|
|
105
|
+
it; an arrangement does not go inside `NavigationSplitView`, `List`,
|
|
106
|
+
`ScrollView` or another container that could make part of it unreachable.
|
|
107
|
+
|
|
108
|
+
## 4. Vertical bars
|
|
109
|
+
|
|
110
|
+
| Job | SwiftUI | UIKit | iOS |
|
|
111
|
+
|---|---|---|---|
|
|
112
|
+
| Bars that can go vertical | `.toolbar` on `NavigationStack` / `NavigationSplitView` | items on a view controller in a navigation controller | |
|
|
113
|
+
| Custom Back or Close | `ToolbarItem(placement: .cancellationAction)` | `leadingItemGroups` | 14 / 16 |
|
|
114
|
+
| Prominent action | `topBarPinnedTrailing` | `pinnedTrailingGroup` | 27 / 16 |
|
|
115
|
+
| Group items | `ToolbarItemGroup` | `UIBarButtonItemGroup` | 14 |
|
|
116
|
+
| Title plus symbol | `Label` | `UIBarButtonItem` title and image | |
|
|
117
|
+
| Overflow order | `visibilityPriority(_:)`, `ToolbarItemVisibilityPriority` (`.automatic`, `.low`, `.high`, `init(higherThan:)`, `init(lowerThan:)`) | `visibilityPriority`, `UIBarButtonItemVisibilityPriority` | 27 |
|
|
118
|
+
| Put items in overflow | `ToolbarOverflowMenu` | `additionalOverflowItems` | 27 / 16 |
|
|
119
|
+
| Keep an item horizontal | `axisBehavior(_:)` with `ToolbarItemAxisBehavior` (`.automatic`, `.horizontalOnly`, `.verticalPreferred`) | `axisBehavior`, `UIBarButtonItem.AxisBehavior` | *(27.1 beta)* |
|
|
120
|
+
| Tab bar versus toolbar when tight | `toolbarVerticalCompressionBehavior(_:)` (`.automatic`, `.prefersTabBar`, `.prefersToolbarItems`) | `UIVerticalBarCompressionBehavior` | *(27.1 beta)* |
|
|
121
|
+
| Opt a screen out | `toolbarVerticalBehavior(.disabled)` | `preferredVerticalBarBehavior`, `setNeedsUpdateOfVerticalBarConfiguration()` | *(27.1 beta)* |
|
|
122
|
+
| Which edge the bar prefers | `toolbarVerticalEdge` environment (`HorizontalEdge?`) | `verticalBarEdge` trait (`UIVerticalBarEdge`) | *(27.1 beta)* |
|
|
123
|
+
| Image under the bar | `backgroundExtensionEffect()` | `UIBackgroundExtensionView` | 26 |
|
|
124
|
+
|
|
125
|
+
```swift
|
|
126
|
+
NavigationStack {
|
|
127
|
+
EditorView()
|
|
128
|
+
.toolbar {
|
|
129
|
+
ToolbarItem(placement: .cancellationAction) {
|
|
130
|
+
Button("Close", systemImage: "xmark") { dismiss() }
|
|
131
|
+
}
|
|
132
|
+
ToolbarItem(placement: .topBarPinnedTrailing) {
|
|
133
|
+
Button("Done", systemImage: "checkmark") { save() }
|
|
134
|
+
}
|
|
135
|
+
ToolbarItemGroup {
|
|
136
|
+
Button("Bold", systemImage: "bold") { toggleBold() }
|
|
137
|
+
Button("Italic", systemImage: "italic") { toggleItalic() }
|
|
138
|
+
}
|
|
139
|
+
.visibilityPriority(.low)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
How items are shown: vertically with their icon; horizontally with icon or
|
|
145
|
+
title (icon preferred); in overflow with both. An item with only a title or a
|
|
146
|
+
custom view is never placed vertically.
|
|
147
|
+
|
|
148
|
+
Contexts that choose differently: inspectors keep horizontal bars; a split
|
|
149
|
+
view uses horizontal bars for sidebar and content columns and vertical bars
|
|
150
|
+
for the detail column; sheets on the outer display go vertical by default.
|
|
151
|
+
|
|
152
|
+
`toolbarVerticalBehavior` is resolved per container: the top view of a
|
|
153
|
+
`NavigationStack`, the selected tab of a `TabView`, the trailing column of a
|
|
154
|
+
`NavigationSplitView`. To hide bars rather than change their axis, use
|
|
155
|
+
`toolbarVisibility(_:for:)`.
|
|
156
|
+
|
|
157
|
+
`toolbarVerticalEdge` reports the preferred edge even when no vertical bar is
|
|
158
|
+
currently visible, and nil where the system never uses one:
|
|
159
|
+
|
|
160
|
+
```swift
|
|
161
|
+
@Environment(\.toolbarVerticalEdge) private var barEdge
|
|
162
|
+
|
|
163
|
+
FloatingPalette()
|
|
164
|
+
.frame(maxWidth: .infinity, alignment: barEdge == .leading ? .leading : .trailing)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 5. Sheets
|
|
168
|
+
|
|
169
|
+
On the inner display, sheets use horizontal toolbars when centred or leading
|
|
170
|
+
and vertical ones when trailing. Choose placement with
|
|
171
|
+
`presentationPlacement(_:)` (iOS 27) or `UISheetPresentationController.preferredPlacement`
|
|
172
|
+
(iOS 27). On the outer display, a sheet with a single action can opt out of the
|
|
173
|
+
vertical bar with `toolbarVerticalBehavior(.disabled)`.
|
|
174
|
+
|
|
175
|
+
## 6. Hinge
|
|
176
|
+
|
|
177
|
+
| | SwiftUI *(27.1 beta)* | UIKit *(27.1 beta)* |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| Observe | `onHingeChange(isEnabled:_:)`, old and new `DeviceHingeContext` | `UIHingeInteraction(updateHandler:)`, `(interaction, update)` |
|
|
180
|
+
| Hinge value | `DeviceHingeContext.hinge: DeviceHinge?` | `Update.hinge: UIHinge?` |
|
|
181
|
+
| Angle | `angle: Angle` | `angle: CGFloat`, radians |
|
|
182
|
+
| Status | `DeviceHinge.Status` struct: `.closed`, `.partiallyOpen`, `.fullyOpen` | `UIHinge.Status` enum: same plus `.unknown` |
|
|
183
|
+
|
|
184
|
+
```swift
|
|
185
|
+
@State private var hingeStatus: DeviceHinge.Status?
|
|
186
|
+
|
|
187
|
+
var body: some View {
|
|
188
|
+
Canvas3DView(tilted: hingeStatus == .partiallyOpen)
|
|
189
|
+
.onHingeChange { _, new in
|
|
190
|
+
hingeStatus = new.hinge?.status
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- `hinge` is nil where there is no hinge; treat that as the normal phone case.
|
|
196
|
+
- The UIKit handler runs with the initial state, on changes, and when the
|
|
197
|
+
interaction moves between hierarchies. It escapes, so capture weakly.
|
|
198
|
+
- Status comes from angle and orientation together; do not rebuild it from
|
|
199
|
+
angle thresholds. Update rate and precision are system policy.
|
|
200
|
+
- Use the hinge for interactions and effects. Layout belongs to reserved
|
|
201
|
+
regions, arrangements and size classes.
|
|
202
|
+
|
|
203
|
+
## 7. Scenes and accessories
|
|
204
|
+
|
|
205
|
+
- `sceneAccessory(content:)` (iOS 27) and UIKit's scene accessory
|
|
206
|
+
registration (`registerSceneAccessory(_:)`) attach content to another
|
|
207
|
+
display, for example a camera capture accessory on the outer display while
|
|
208
|
+
the app runs on the inner one. See Apple's article on registering a camera
|
|
209
|
+
capture accessory on iPhone Duo.
|
|
210
|
+
- New windows depend on what the current display allows. Prefer
|
|
211
|
+
`UIWindowScene.ActivationAction` for "open in new window" menu items, and
|
|
212
|
+
handle a failed scene request instead of assuming success.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Fixed assumptions: grep list and replacements
|
|
2
|
+
|
|
3
|
+
Run these from the repository root. Every hit is a candidate, not a verdict:
|
|
4
|
+
read the surrounding code, decide whether it affects layout, and confirm on
|
|
5
|
+
the iPhone Duo simulator. Exclude vendored and generated code from the count.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
1. The search
|
|
10
|
+
2. Orientation
|
|
11
|
+
3. The screen
|
|
12
|
+
4. Cached sizes
|
|
13
|
+
5. Idiom and size class
|
|
14
|
+
6. Device sizes and thresholds
|
|
15
|
+
7. Insets
|
|
16
|
+
8. Bars
|
|
17
|
+
9. Media
|
|
18
|
+
10. Recording the result
|
|
19
|
+
|
|
20
|
+
## 1. The search
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
rg -n --type swift \
|
|
24
|
+
-e 'UIScreen\.main' \
|
|
25
|
+
-e 'UIScreen\.screens' \
|
|
26
|
+
-e 'UIDevice\.current\.orientation' \
|
|
27
|
+
-e 'interfaceOrientation' \
|
|
28
|
+
-e 'statusBarOrientation' \
|
|
29
|
+
-e 'userInterfaceIdiom' \
|
|
30
|
+
-e 'horizontalSizeClass\s*==\s*\.regular' \
|
|
31
|
+
-e 'UIWindow\(frame:' \
|
|
32
|
+
-e 'safeAreaInsets\.(left|right|top|bottom)\s*\*\s*2' \
|
|
33
|
+
-e '(width|height)\s*(==|>=|<=|>|<)\s*(320|375|390|393|402|414|428|430|440)\b' \
|
|
34
|
+
-e 'UIToolbar\(|UINavigationBar\(|UITabBar\(' \
|
|
35
|
+
-e 'scaleAspectFill|contentMode:\s*\.fill' \
|
|
36
|
+
.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Add Objective-C (`--type objc`) and storyboards (`-g '*.storyboard'` for
|
|
40
|
+
fixed-size constraints) when the project has them.
|
|
41
|
+
|
|
42
|
+
## 2. Orientation
|
|
43
|
+
|
|
44
|
+
Hits: `UIDevice.current.orientation`, `interfaceOrientation` (including
|
|
45
|
+
`windowScene.effectiveGeometry.interfaceOrientation`), `statusBarOrientation`.
|
|
46
|
+
|
|
47
|
+
Why: on a foldable device orientation no longer says whether the app is wide
|
|
48
|
+
or tall, and Apple's guidance is not to use `UIInterfaceOrientation` for
|
|
49
|
+
layout decisions.
|
|
50
|
+
|
|
51
|
+
Replace: compare the width and height of the space you have, `view.bounds` in
|
|
52
|
+
a view controller, `bounds` of the superview in a view, the size from
|
|
53
|
+
`GeometryReader` or `onGeometryChange` in SwiftUI. Keep orientation only for
|
|
54
|
+
things that are about the device's physical attitude (camera capture
|
|
55
|
+
rotation), not about layout.
|
|
56
|
+
|
|
57
|
+
## 3. The screen
|
|
58
|
+
|
|
59
|
+
Hits: `UIScreen.main` (deprecated in iOS 26), `UIScreen.screens`,
|
|
60
|
+
`UIWindow(frame: UIScreen.main.bounds)`.
|
|
61
|
+
|
|
62
|
+
| Instead of | Use |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `UIScreen.main.bounds` | `view.bounds`, `window.bounds`, `GeometryReader`, `onGeometryChange` |
|
|
65
|
+
| `UIScreen.main.scale` | `traitCollection.displayScale`, `@Environment(\.displayScale)` |
|
|
66
|
+
| `UIWindow(frame: UIScreen.main.bounds)` | `UIWindow(windowScene:)` |
|
|
67
|
+
| A stored `UIScreen` | `view.window?.windowScene?.screen`, read when needed |
|
|
68
|
+
|
|
69
|
+
## 4. Cached sizes
|
|
70
|
+
|
|
71
|
+
Hard to grep; look for sizes stored in properties at `viewDidLoad`,
|
|
72
|
+
`viewIsAppearing`, `init`, `onAppear`, or a `GeometryReader` value copied into
|
|
73
|
+
`@State` once.
|
|
74
|
+
|
|
75
|
+
Why: folding and unfolding resizes the app during a session. A size read at
|
|
76
|
+
launch is wrong after the first fold.
|
|
77
|
+
|
|
78
|
+
Replace: do size-dependent layout in `viewDidLayoutSubviews` or
|
|
79
|
+
`layoutSubviews`; use `viewWillTransition(to:with:)` for work tied to the
|
|
80
|
+
change itself; in SwiftUI derive layout from the current geometry every time,
|
|
81
|
+
or keep it current with `onGeometryChange`.
|
|
82
|
+
|
|
83
|
+
## 5. Idiom and size class
|
|
84
|
+
|
|
85
|
+
Hits: `userInterfaceIdiom == .pad`, `horizontalSizeClass == .regular` used to
|
|
86
|
+
mean "iPad", and code that assumes iPhone is always compact.
|
|
87
|
+
|
|
88
|
+
Why: the inner display is regular width on an iPhone. An iPad-only layout
|
|
89
|
+
branch now runs on a phone, and a "phone means compact" branch never expects
|
|
90
|
+
regular.
|
|
91
|
+
|
|
92
|
+
Replace: branch on size class and available space only. Check both
|
|
93
|
+
directions: code that fires on regular, and code that assumes compact.
|
|
94
|
+
|
|
95
|
+
## 6. Device sizes and thresholds
|
|
96
|
+
|
|
97
|
+
Hits: comparisons with known iPhone widths or heights, device lookup tables,
|
|
98
|
+
"if width > 390" breakpoints.
|
|
99
|
+
|
|
100
|
+
Why: no table contains this device, and Split View produces sizes no device
|
|
101
|
+
has.
|
|
102
|
+
|
|
103
|
+
Replace: size classes (compact for the outer display, regular for the inner),
|
|
104
|
+
`ViewThatFits`, `containerRelativeFrame`, proportional and intrinsic sizing.
|
|
105
|
+
|
|
106
|
+
## 7. Insets
|
|
107
|
+
|
|
108
|
+
Hits: `safeAreaInsets.left * 2`, `width - 2 * inset`, `insets.left` used for
|
|
109
|
+
both sides, padding that mirrors one edge onto the other.
|
|
110
|
+
|
|
111
|
+
Why: side-mounted bars make safe areas and layout margins asymmetric, and the
|
|
112
|
+
heavy side depends on pose and Split View position.
|
|
113
|
+
|
|
114
|
+
Replace: inset each edge by its own value, or constrain to the safe area
|
|
115
|
+
layout guide and layout margins and let the system resolve each edge.
|
|
116
|
+
|
|
117
|
+
## 8. Bars
|
|
118
|
+
|
|
119
|
+
Hits: `UIToolbar(`, `UINavigationBar(`, `UITabBar(` created by hand, or a
|
|
120
|
+
SwiftUI `HStack` styled as a bar pinned to the top or bottom.
|
|
121
|
+
|
|
122
|
+
Why: only bars provided by navigation containers take part in vertical
|
|
123
|
+
placement. A custom bar stays where it is and collides with the system's
|
|
124
|
+
vertical controls.
|
|
125
|
+
|
|
126
|
+
Replace: toolbar items on `NavigationStack` / `NavigationSplitView` with
|
|
127
|
+
`.toolbar`, or on a view controller inside a navigation controller; `TabView`
|
|
128
|
+
or `UITabBarController` for tabs.
|
|
129
|
+
|
|
130
|
+
## 9. Media
|
|
131
|
+
|
|
132
|
+
Hits: `scaleAspectFill`, `.aspectRatio(contentMode: .fill)` on hero images
|
|
133
|
+
and video.
|
|
134
|
+
|
|
135
|
+
Why: wider displays crop more of the image and can lose the subject.
|
|
136
|
+
|
|
137
|
+
Replace: choose fill or fit from the current size or aspect ratio, crop around
|
|
138
|
+
a focal point, and extend backgrounds under bars with
|
|
139
|
+
`backgroundExtensionEffect()` rather than stretching the image.
|
|
140
|
+
|
|
141
|
+
## 10. Recording the result
|
|
142
|
+
|
|
143
|
+
For each hit, record `file:line`, the category, keep or fix, and for fixes the
|
|
144
|
+
replacement. Separate "confirmed on the simulator" from "found in code only".
|
|
145
|
+
Pose-dependent behaviour is not proven until it has been seen running.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Poses, panes and the design review
|
|
2
|
+
|
|
3
|
+
Design guidance for iPhone Duo. The rules marked HIG come from Apple's
|
|
4
|
+
Designing for iPhone Duo page; the pattern table is a recommendation built on
|
|
5
|
+
those rules and on size classes, and should be adapted to the app's content.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
1. Poses
|
|
10
|
+
2. Pose to pattern
|
|
11
|
+
3. Using the inner display
|
|
12
|
+
4. Dual-pane rules
|
|
13
|
+
5. Controls on the side
|
|
14
|
+
6. The fold
|
|
15
|
+
7. Review checklist
|
|
16
|
+
|
|
17
|
+
## 1. Poses
|
|
18
|
+
|
|
19
|
+
People hold and set down iPhone Duo in several ways (HIG): closed, using the
|
|
20
|
+
outer display; open flat on the inner display; partially folded like a book;
|
|
21
|
+
placed on a surface; standing on its edges. Every pose can also be rotated,
|
|
22
|
+
and Split View can put two apps side by side on the inner display.
|
|
23
|
+
|
|
24
|
+
Supporting poses does not mean a custom layout per pose (HIG). A compact
|
|
25
|
+
width layout for the outer display and a regular width layout for the inner
|
|
26
|
+
display cover the fundamentals; the existing layout expands into the space.
|
|
27
|
+
|
|
28
|
+
## 2. Pose to pattern
|
|
29
|
+
|
|
30
|
+
| Pose | Size class | What usually works |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| Closed, outer display | compact width | The phone layout. Bars on the side free vertical space; content offset from the bar side |
|
|
33
|
+
| Open, inner display, landscape | regular width | One more level of hierarchy: list and detail side by side, or content reflowed into columns. Bars stay on the side |
|
|
34
|
+
| Open, inner display, portrait | regular width | Same hierarchy as landscape; horizontal bars return because vertical space is plentiful |
|
|
35
|
+
| Partially folded (book) | regular width | A split that rebalances around the fold; even column counts in grids; nothing tappable in the curve |
|
|
36
|
+
| On a surface, partly folded | regular width | Viewing on the upper part, touch on the lower, stable part; suits media and hands-free use |
|
|
37
|
+
| Standing on edges | depends on orientation | Glanceable, hands-free content with few controls |
|
|
38
|
+
| Split View | either, per half | Each app keeps its controls on its outer edge; the app must work at half width |
|
|
39
|
+
|
|
40
|
+
The on-surface layout is optional and still has to offer every control the
|
|
41
|
+
other poses offer.
|
|
42
|
+
|
|
43
|
+
## 3. Using the inner display
|
|
44
|
+
|
|
45
|
+
A stretched phone layout is the failure to avoid. Options, in rough order of
|
|
46
|
+
cost:
|
|
47
|
+
|
|
48
|
+
- **Split view**: `NavigationSplitView` shows list and detail together when
|
|
49
|
+
open and collapses to a stack when closed. The hierarchy is the same; the
|
|
50
|
+
inner display shows one more level of it (HIG). Mail shows the list or a
|
|
51
|
+
message when closed and both side by side when open.
|
|
52
|
+
- **Reflow**: a single column becomes two columns when width allows
|
|
53
|
+
(`ViewThatFits`, `AnyLayout`, adaptive grids).
|
|
54
|
+
- **Arrangement**: two related views (now playing and lyrics, controls and
|
|
55
|
+
video) in an `ArrangementView` that adapts to the fold.
|
|
56
|
+
- **Sidebar tabs**: a sidebar-adaptable tab view for information-dense apps.
|
|
57
|
+
|
|
58
|
+
## 4. Dual-pane rules
|
|
59
|
+
|
|
60
|
+
- Same functions and state on both displays (HIG). Opening or closing the
|
|
61
|
+
device mid-task must not lose a selection, a scroll position or a draft.
|
|
62
|
+
- Never tie a function to a pose (HIG). Everything reachable in one pose is
|
|
63
|
+
reachable in all of them, even if it moves into overflow.
|
|
64
|
+
- The secondary pane depends on the primary: selecting in the list drives the
|
|
65
|
+
detail. When the device closes, the detail the person was reading should be
|
|
66
|
+
what they see, not the list.
|
|
67
|
+
- Keep controls with the content they act on (HIG). Actions for the list sit
|
|
68
|
+
above the list pane, not in the side bar beside the detail.
|
|
69
|
+
- Each pane keeps its own safe area and margins; do not let one pane's insets
|
|
70
|
+
bleed into the other.
|
|
71
|
+
- Prefer containers that rebalance themselves around the fold over manual
|
|
72
|
+
positioning (HIG), and in grids prefer an even number of columns so content
|
|
73
|
+
divides cleanly.
|
|
74
|
+
|
|
75
|
+
## 5. Controls on the side
|
|
76
|
+
|
|
77
|
+
- Follow the system's vertical placement and do not override it without a
|
|
78
|
+
strong reason (HIG); it is one of the device's core patterns.
|
|
79
|
+
- Top of the vertical axis: Back or Close, then prominent actions such as
|
|
80
|
+
Done; remaining items keep their original groupings (HIG).
|
|
81
|
+
- Give every item a symbol and a title; keep text-only buttons to a minimum,
|
|
82
|
+
because text items stay in a horizontal bar (HIG).
|
|
83
|
+
- Assign visibility priority so frequent actions and items with badges stay
|
|
84
|
+
visible longest (HIG).
|
|
85
|
+
- Use the system overflow menu instead of a custom one; reserve the ellipsis
|
|
86
|
+
for overflow (HIG).
|
|
87
|
+
- Content next to side controls is asymmetric. Offset content by the safe
|
|
88
|
+
area by default; centre on the full display only for immersive,
|
|
89
|
+
non-scrolling screens with nothing interactive under the controls; or let a
|
|
90
|
+
background span the full width while the scrollable, interactive content
|
|
91
|
+
stays inset (HIG).
|
|
92
|
+
|
|
93
|
+
## 6. The fold
|
|
94
|
+
|
|
95
|
+
- Keep interactive elements out of the folding region (HIG). System controls
|
|
96
|
+
are moved aside automatically; custom ones use reserved regions.
|
|
97
|
+
- Move as little as possible as the device folds (HIG). Small adjustments
|
|
98
|
+
that keep elements visible beat controls that vanish or jump.
|
|
99
|
+
- Scrolling content may pass through the fold; fixed text and controls
|
|
100
|
+
should not rest in it.
|
|
101
|
+
|
|
102
|
+
## 7. Review checklist
|
|
103
|
+
|
|
104
|
+
Use with `ios-design-review` for the general visual pass.
|
|
105
|
+
|
|
106
|
+
1. Is anything interactive in the fold or under the side controls?
|
|
107
|
+
2. Is any function or piece of state available in one pose but not another?
|
|
108
|
+
3. Does state survive opening, closing and folding mid-task?
|
|
109
|
+
4. Are there fixed widths or device breakpoints instead of size classes?
|
|
110
|
+
5. Do toolbar items have symbols and titles, sensible priorities, and does the
|
|
111
|
+
overflow hold the right things?
|
|
112
|
+
6. Does the inner display do better than stretching (split, reflow,
|
|
113
|
+
arrangement)?
|
|
114
|
+
7. Is content offset from the side controls, deliberately centred, or mixed
|
|
115
|
+
with every control inside the inset area?
|
|
116
|
+
8. Does the screen hold up in Split View on both sides, at half width?
|
|
117
|
+
9. Do custom components reimplement fold avoidance the system components
|
|
118
|
+
would have provided?
|
|
119
|
+
10. Are controls next to the content they affect?
|
|
120
|
+
11. Do grids divide evenly around the fold?
|
|
121
|
+
12. Which of the above were seen on the simulator, and which only reasoned
|
|
122
|
+
from design files or code?
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ios-sf-symbols
|
|
3
|
+
description: "SF Symbols in SwiftUI and UIKit: rendering modes, variable values, symbol effects including Draw On and Off, matching weight and scale to text, custom symbols and accessibility labels. Use when picking, styling, animating or reviewing symbols, or building a custom symbol."
|
|
4
|
+
metadata:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
|
+
date_added: "2026-10-08"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# SF Symbols
|
|
10
|
+
|
|
11
|
+
SF Symbols are vector glyphs drawn to sit with San Francisco text: nine
|
|
12
|
+
weights and three scales that line up with the font, layers that take colour,
|
|
13
|
+
and built-in animations. Using them well is mostly about letting them follow
|
|
14
|
+
the text and the container instead of sizing them by hand.
|
|
15
|
+
|
|
16
|
+
## Versions and availability
|
|
17
|
+
|
|
18
|
+
Symbols and symbol features introduced in a given year are not available on
|
|
19
|
+
earlier systems, so check both the symbol's availability in the SF Symbols app
|
|
20
|
+
and the API's introduction version.
|
|
21
|
+
|
|
22
|
+
| Capability | API | iOS |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| Rendering modes | `symbolRenderingMode(_:)`, `SymbolRenderingMode` | 15 |
|
|
25
|
+
| Variants | `symbolVariant(_:)`, `SymbolVariants` | 15 |
|
|
26
|
+
| Variable value | `Image(systemName:variableValue:)` | 16 |
|
|
27
|
+
| Symbol effects | `symbolEffect(_:options:value:)`, `symbolEffect(_:options:isActive:)`, `contentTransition(.symbolEffect(...))` | 17 |
|
|
28
|
+
| Wiggle, Rotate, Breathe | `WiggleSymbolEffect`, `RotateSymbolEffect`, `BreatheSymbolEffect` | 18 |
|
|
29
|
+
| Draw On, Draw Off | `DrawOnSymbolEffect`, `DrawOffSymbolEffect` (`.drawOn`, `.drawOff`) | 26 |
|
|
30
|
+
| Variable Draw | `symbolVariableValueMode(_:)` with `.draw` | 26 |
|
|
31
|
+
| Gradient rendering | `symbolColorRenderingMode(_:)` with `.gradient` | 26 |
|
|
32
|
+
|
|
33
|
+
SF Symbols 7 introduced Draw, Variable Draw and gradients. The current SF
|
|
34
|
+
Symbols app (27 releases) adds semantic search and new symbols. Check
|
|
35
|
+
developer.apple.com/sf-symbols for the current app before relying on a symbol
|
|
36
|
+
that may be new.
|
|
37
|
+
|
|
38
|
+
## Sizing with text
|
|
39
|
+
|
|
40
|
+
Symbols take their size and weight from the font, which is what keeps them
|
|
41
|
+
aligned and scaling with Dynamic Type.
|
|
42
|
+
|
|
43
|
+
```swift
|
|
44
|
+
Label("Downloads", systemImage: "arrow.down.circle")
|
|
45
|
+
.font(.headline)
|
|
46
|
+
|
|
47
|
+
Image(systemName: "bell")
|
|
48
|
+
.font(.body)
|
|
49
|
+
.imageScale(.large)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- Set size with `.font(...)` and a text style, not `.resizable().frame(...)`.
|
|
53
|
+
A resized image stops scaling with Dynamic Type and loses weight matching.
|
|
54
|
+
- Use `imageScale(_:)` (small, medium, large) to change emphasis relative to
|
|
55
|
+
the text without breaking the weight match.
|
|
56
|
+
- Match weight to adjacent text (`.fontWeight(.semibold)` on both).
|
|
57
|
+
- In UIKit, `UIImage.SymbolConfiguration(textStyle:)` or
|
|
58
|
+
`init(font:scale:)` does the same job.
|
|
59
|
+
|
|
60
|
+
## Rendering modes
|
|
61
|
+
|
|
62
|
+
| Mode | What it does | Good for |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| Monochrome | One colour for every layer | Toolbars, lists, most UI |
|
|
65
|
+
| Hierarchical | One colour, layers at decreasing opacity | Depth without extra colours |
|
|
66
|
+
| Palette | One explicit colour per layer | Brand or status colour pairs |
|
|
67
|
+
| Multicolor | The symbol's intrinsic colours | Weather, files, recognisable objects |
|
|
68
|
+
|
|
69
|
+
```swift
|
|
70
|
+
Image(systemName: "cloud.sun.rain.fill")
|
|
71
|
+
.symbolRenderingMode(.hierarchical)
|
|
72
|
+
.foregroundStyle(.tint)
|
|
73
|
+
|
|
74
|
+
Image(systemName: "person.crop.circle.badge.checkmark")
|
|
75
|
+
.symbolRenderingMode(.palette)
|
|
76
|
+
.foregroundStyle(.green, .secondary)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Gradient rendering (iOS 26) adds a light linear gradient from a single colour
|
|
80
|
+
in any mode: `.symbolColorRenderingMode(.gradient)`. It looks best at larger
|
|
81
|
+
sizes. Prefer system colours in every mode so symbols adapt to dark mode,
|
|
82
|
+
vibrancy and Increase Contrast. Check the automatic choice at small sizes and
|
|
83
|
+
on busy backgrounds, where a different mode may read better.
|
|
84
|
+
|
|
85
|
+
## Variants
|
|
86
|
+
|
|
87
|
+
Outline is the default and sits best next to text. Fill gives emphasis and is
|
|
88
|
+
what tab bars prefer; slash marks something unavailable; enclosed shapes help
|
|
89
|
+
legibility at small sizes. Containers often pick the variant (a tab bar
|
|
90
|
+
chooses fill), so set `symbolVariant(_:)` only when the context does not.
|
|
91
|
+
|
|
92
|
+
## Variable values
|
|
93
|
+
|
|
94
|
+
A variable value (0 to 1) shows a level: signal, volume, progress.
|
|
95
|
+
|
|
96
|
+
```swift
|
|
97
|
+
Image(systemName: "wifi", variableValue: strength)
|
|
98
|
+
|
|
99
|
+
Image(systemName: "thermometer.high", variableValue: level)
|
|
100
|
+
.symbolVariableValueMode(.draw)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Variable Color changes layer opacity at thresholds; Variable Draw (iOS 26)
|
|
104
|
+
draws the path to the value, which reads more precisely. Use variable values
|
|
105
|
+
to show change, not depth; hierarchical rendering is for depth.
|
|
106
|
+
|
|
107
|
+
## Effects
|
|
108
|
+
|
|
109
|
+
Effects tell people that something happened or is happening. Each has a
|
|
110
|
+
meaning; pick by meaning, not by look.
|
|
111
|
+
|
|
112
|
+
| Effect | Use | Trigger |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| Bounce | An action happened | `value:` changes |
|
|
115
|
+
| Pulse, Breathe | Ongoing activity | `isActive:` |
|
|
116
|
+
| Variable Color | Progress or connecting | `isActive:` |
|
|
117
|
+
| Wiggle | Draw attention to something easy to miss | `value:` |
|
|
118
|
+
| Rotate | Work in progress, rotating parts | `isActive:` |
|
|
119
|
+
| Scale | Persistent emphasis on a selection | `isActive:` |
|
|
120
|
+
| Appear, Disappear | Show or hide a symbol | `isActive:` or transition |
|
|
121
|
+
| Draw On, Draw Off | Draw in or out along the path (iOS 26) | `isActive:` or transition |
|
|
122
|
+
| Replace, Magic Replace (18) | Swap one symbol for a related one | `contentTransition` |
|
|
123
|
+
|
|
124
|
+
```swift
|
|
125
|
+
Image(systemName: "bell")
|
|
126
|
+
.symbolEffect(.bounce, value: unreadCount)
|
|
127
|
+
|
|
128
|
+
Image(systemName: isMuted ? "speaker.slash" : "speaker.wave.2")
|
|
129
|
+
.contentTransition(.symbolEffect(.replace))
|
|
130
|
+
|
|
131
|
+
Image(systemName: "checkmark.circle")
|
|
132
|
+
.symbolEffect(.drawOff.byLayer, isActive: !isSaved)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Use effects sparingly; several animated symbols on one screen compete. Repeat
|
|
136
|
+
indefinitely only while the condition holds. Respect Reduce Motion: read
|
|
137
|
+
`accessibilityReduceMotion` and drop decorative repeating effects when it is
|
|
138
|
+
on, keeping the state change itself visible. Full effect options and the
|
|
139
|
+
UIKit equivalents are in `references/effects-and-custom-symbols.md`.
|
|
140
|
+
|
|
141
|
+
## Custom symbols
|
|
142
|
+
|
|
143
|
+
When no system symbol fits, build one from the SF Symbols template rather than
|
|
144
|
+
drawing an icon from scratch, so it gets weights, scales, rendering modes and
|
|
145
|
+
animations. In short: export the closest system symbol's template from the SF
|
|
146
|
+
Symbols app, edit it in a vector tool, import it back, annotate layers (and
|
|
147
|
+
Draw guide points if it animates), test every effect, export, and add it to an
|
|
148
|
+
asset catalog as a symbol image. Load it with `Image("name")` or
|
|
149
|
+
`UIImage(named:)`. The full process is in the reference.
|
|
150
|
+
|
|
151
|
+
Symbols that depict Apple products or features cannot be customised; the SF
|
|
152
|
+
Symbols app marks them with an Info badge.
|
|
153
|
+
|
|
154
|
+
## Accessibility
|
|
155
|
+
|
|
156
|
+
- Icon-only controls need a label. `Label("Share", systemImage: ...)` gives
|
|
157
|
+
VoiceOver and overflow menus a title even when only the icon shows.
|
|
158
|
+
- Use `.accessibilityLabel(...)` when the label must differ from visible text,
|
|
159
|
+
and hide purely decorative symbols with `.accessibilityHidden(true)`.
|
|
160
|
+
- Custom symbols need an accessibility description; VoiceOver cannot infer one.
|
|
161
|
+
- Directional symbols have right-to-left variants; custom symbols need their
|
|
162
|
+
directionality set when exported.
|
|
163
|
+
|
|
164
|
+
## Not in app icons
|
|
165
|
+
|
|
166
|
+
The SF Symbols licence prohibits using symbols, or confusingly similar images,
|
|
167
|
+
in app icons, logos or any trademarked use. Draw the icon's artwork
|
|
168
|
+
separately; see `hig-app-icons`.
|
|
169
|
+
|
|
170
|
+
## References
|
|
171
|
+
|
|
172
|
+
- `references/effects-and-custom-symbols.md`: effect options, UIKit API, custom symbol workflow, review checklist.
|
|
173
|
+
- HIG SF Symbols: https://developer.apple.com/design/human-interface-guidelines/sf-symbols
|
|
174
|
+
- SF Symbols app: https://developer.apple.com/sf-symbols/
|
|
175
|
+
- Symbols framework: https://developer.apple.com/documentation/symbols
|
|
176
|
+
- Configuring and displaying symbol images: https://developer.apple.com/documentation/uikit/configuring-and-displaying-symbol-images-in-your-ui
|
|
177
|
+
- Creating custom symbols: https://developer.apple.com/documentation/technologyoverviews/custom-sf-symbols
|