← Files Build iOS AppsARCHIVED FILE
skills/swiftui-ui-patterns/references/media.md
1.99 KB · Oct 5, 2026 · 18:37 UTC
# Media (images, video, viewer)
## Intent
Use consistent patterns for loading images, previewing media, and presenting a full-screen viewer.
## Core patterns
- Use `LazyImage` (or `AsyncImage`) for remote images with loading states.
- Prefer a lightweight preview component for inline media.
- Use a shared viewer state (e.g., `QuickLook`) to present a full-screen media viewer.
- Use `openWindow` for desktop/visionOS and a sheet for iOS.
## Example: inline media preview
```swift
struct MediaPreviewRow: View {
@Environment(QuickLook.self) private var quickLook
let attachments: [MediaAttachment]
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(attachments) { attachment in
LazyImage(url: attachment.previewURL) { state in
if let image = state.image {
image.resizable().aspectRatio(contentMode: .fill)
} else {
ProgressView()
}
}
.frame(width: 120, height: 120)
.clipped()
.onTapGesture {
quickLook.prepareFor(
selectedMediaAttachment: attachment,
mediaAttachments: attachments
)
}
}
}
}
}
}
```
## Example: global media viewer sheet
```swift
struct AppRoot: View {
@State private var quickLook = QuickLook.shared
var body: some View {
content
.environment(quickLook)
.sheet(item: $quickLook.selectedMediaAttachment) { selected in
MediaUIView(selectedAttachment: selected, attachments: quickLook.mediaAttachments)
}
}
}
```
## Design choices to keep
- Keep previews lightweight; load full media in the viewer.
- Use shared viewer state so any view can open media without prop-drilling.
- Use a single entry point for the viewer (sheet/window) to avoid duplicates.
## Pitfalls
- Avoid loading full-size images in list rows; use resized previews.
- Don’t present multiple viewer sheets at once; keep a single source of truth.
SHA-256: 055b26c2ae925c16de71cdbc46ef9466185eb9004398cd065318e574d85eda83