mcpField
V
visionos-widgets

visionos-widgets

github.com/rshankras设计与 UI83873 次安装14 周前更新
代码仓库

关于 visionos-widgets

面向 visionOS 空间环境中 Widget 开发的指南,介绍安装方式、纹理、距离感知布局、Widget 系列、背景和渲染模式。

主要功能

  1. 01凸起与嵌入式安装
  2. 02玻璃与纸张纹理
  3. 03距离感知的细节级别
  4. 04空间 Widget 系列
  5. 05背景与渲染模式处理

适用场景

  1. 01将现有 iOS Widget 适配到 visionOS
  2. 02为桌面或墙面选择安装方式
  3. 03在远距离简化 Widget 内容
  4. 04支持全彩与强调色渲染

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rshankras/claude-code-apple-skills --skill visionos-widgets

安装后在 Claude Code 中输入/visionos-widgets确认已加载。

详细介绍

visionOS 小组件

介绍在 visionOS 空间中呈现的小组件构建模式,涵盖安装样式、纹理、支持距离感知的详细程度、空间小组件系列和渲染模式。

此技能的触发条件

在以下情况下使用此技能:

  • 用户要求创建或改造 visionOS 小组件
  • 提到 安装样式(凸起式、嵌入式)
  • 希望为小组件添加 玻璃或纸张纹理
  • 询问小组件中的 距离感知 或 详细程度
  • 提到 空间小组件系列 或 .systemExtraLargePortrait
  • 希望控制 容器背景 或 渲染模式(全彩或强调色)
  • 将现有 iOS/iPadOS 小组件移植到 visionOS

决策树

What do you need for your visionOS widget?
|
+- Where should the widget appear?
|  +- On a surface (table, shelf) -> .elevated (default)
|  +- Embedded in a wall -> .recessed
|  +- Both -> .supportedMountingStyles([.elevated, .recessed])
|
+- What visual treatment?
|  +- Transparent, blends with environment -> .glass (default)
|  +- Opaque, poster-like appearance -> .paper
|
+- How should it respond to user distance?
|  +- Full detail when close -> @Environment(\.levelOfDetail) == .default
|  +- Simplified when far -> @Environment(\.levelOfDetail) == .simplified
|
+- What size families?
|  +- Standard -> .systemSmall, .systemMedium, .systemLarge, .systemExtraLarge
|  +- Tall portrait -> .systemExtraLargePortrait (visionOS only)
|
+- How should colors render?
|  +- Full color (default) -> No extra work
|  +- System-tinted monochrome -> Mark backgrounds with .containerBackground(for:)

API 可用性

API最低版本说明
visionOS 上的 WidgetKitvisionOS 1.0基本小组件支持
.containerBackground(for: .widget)visionOS 1.0标记可移除的背景
@Environment(\.showsWidgetContainerBackground)visionOS 1.0检查背景是否可见
.supportedMountingStyles()visionOS 2.0凸起式和嵌入式放置
.widgetTexture(.glass / .paper)visionOS 2.0小组件表面材质
@Environment(\.levelOfDetail)visionOS 2.0支持距离感知的布局
.systemExtraLargePortraitvisionOS 2.0高纵向小组件系列

完整小组件示例

此示例展示了如何结合使用安装样式、纹理、小组件系列和距离感知:

struct MyWidget: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(
            kind: "com.example.mywidget",
            provider: Provider()
        ) { entry in
            MyWidgetView(entry: entry)
        }
        .supportedFamilies([
            .systemSmall, .systemMedium, .systemLarge,
            .systemExtraLarge, .systemExtraLargePortrait
        ])
        .supportedMountingStyles([.elevated, .recessed])
        .widgetTexture(.glass)        // .glass is default, .paper for opaque
    }
}

安装样式:.elevated(默认)会放置在桌面等表面上。.recessed 会嵌入墙面,如同装裱好的画作。省略 .supportedMountingStyles() 即仅使用凸起式。嵌入式仅适用于垂直表面;放置在水平表面时始终采用凸起式。在水平表面上,系统还会轻微倾斜小组件,使其朝向用户;请针对这个角度进行设计,而不是试图抵消它。

纹理:.glass(默认)与环境融为一体;.paper 不透明,最适合丰富的图像内容。

空间行为(WWDC25)

小组件是固定在实体表面上的房间装饰物——它们会在不同会话、房间切换和电源循环期间保留,并且一个房间中可以同时存在多个实例。

  • 用户调整大小:用户可以通过角落控件将小组件缩放到模板尺寸的 75% 至 125%——布局必须适应整个范围。
  • 边框:用户可以从 五种边框宽度(从细到粗)中选择,且宽度独立于模板尺寸。嵌入式样式会固定边框宽度。
  • 边框着色:小组件边框始终会应用用户的颜色色调,无法选择退出。即使背景选择不应用色调,前景内容也必须在全部 7 种浅色和 7 种深色系统调色板下清晰可辨。
  • 资源:小组件以真实世界的尺寸渲染——请提供高分辨率资源,确保图像在近距离观看时依然清晰。

距离感知(详细程度)

系统会根据用户距离,在 .default(近)和 .simplified(远)之间自动切换,并带有动画效果——可通过降低内容密度、放大关键信息来简化布局。

struct MyWidgetView: View {
    let entry: Provider.Entry
    @Environment(\.levelOfDetail) private var levelOfDetail

    var body: some View {
        switch levelOfDetail {
        case .default:
            VStack(alignment: .leading, spacing: 8) {
                Text(entry.title).font(.headline)
                Text(entry.subtitle).font(.subheadline).foregroundStyle(.secondary)
                DetailChart(data: entry.chartData)
            }
            .padding()
        case .simplified:
            VStack(spacing: 4) {
                Image(systemName: entry.iconName).font(.largeTitle)
                Text(entry.title).font(.headline)
            }
            .padding()
        @unknown default:
            Text(entry.title).padding()
        }
    }
}

务必处理 @unknown default,以确保向前兼容。

小组件系列

系列说明
.systemSmall紧凑正方形——用于一目了然的信息
.systemMedium宽矩形——用于双列布局或列表预览
.systemLarge大型正方形——用于图表和详细内容
.systemExtraLarge超大型横向布局——用于仪表板
.systemExtraLargePortrait超大型纵向布局——仅限 visionOS;用于墙面装饰的“醒目”小组件

在多平台目标中,为仅限 visionOS 的小组件系列添加保护条件:

.supportedFamilies({
    var families: [WidgetFamily] = [.systemSmall, .systemMedium, .systemLarge]
    #if os(visionOS)
    families.append(.systemExtraLargePortrait)
    #endif
    return families
}())

容器背景和渲染模式

在强调色渲染模式下,系统会移除背景并应用色调。请标记可移除的背景,确保小组件在两种模式下都能正确渲染。

struct MyWidgetView: View {
    let entry: Provider.Entry
    @Environment(\.showsWidgetContainerBackground) var showsBackground

    var body: some View {
        VStack {
            Image(systemName: "star.fill").font(.largeTitle)
            Text(entry.title)
                .font(.headline)
                .foregroundStyle(showsBackground ? .white : .primary)
        }
        .padding()
        .containerBackground(for: .widget) {
            LinearGradient(
                colors: [.blue, .purple],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
        }
    }
}
  • 全彩(默认):所有颜色均按原样渲染。
  • 强调色:容器背景会被移除;系统会应用单色调。

预览 visionOS 小组件

#Preview("Close Up", as: .systemSmall) {
    MyWidget()
} timelineProvider: {
    Provider()
}

#Preview("Extra Large Portrait", as: .systemExtraLargePortrait) {
    MyWidget()
} timelineProvider: {
    Provider()
}

五大常见错误

#错误修复方法
1缺少 .containerBackground(for: .widget)——强调模式下会显示空白始终使用 .containerBackground(for: .widget) { } 包裹背景
2忽略 levelOfDetail——从房间另一端看时,详细视图难以阅读提供 .simplified 布局,使用更大的文字和更少的元素
3在 iOS 上使用 .systemExtraLargePortrait——导致构建错误或运行时崩溃使用 #if os(visionOS) 或仅面向 visionOS 的目标进行条件限制
4硬编码与玻璃质感冲突的颜色使用 .foregroundStyle(.primary / .secondary) 和系统颜色
5levelOfDetail 的 switch 中没有 @unknown default始终包含此项,以确保向前兼容
反模式
// ❌ No container background — accented mode shows nothing
struct BadWidgetView: View {
    var body: some View {
        ZStack {
            Color.blue  // Not marked as removable
            Text("Hello")
        }
    }
}

// ✅ Background marked as removable
struct GoodWidgetView: View {
    var body: some View {
        Text("Hello")
            .containerBackground(for: .widget) { Color.blue }
    }
}
// ❌ Same complex layout at all distances
struct BadProximityView: View {
    var body: some View {
        VStack {
            Text(entry.title).font(.caption2)  // Unreadable far away
            DetailChart(data: entry.data)
        }
    }
}

// ✅ Simplified layout when far away
struct GoodProximityView: View {
    @Environment(\.levelOfDetail) private var levelOfDetail
    var body: some View {
        switch levelOfDetail {
        case .default: DetailedLayout(entry: entry)
        case .simplified: SimplifiedLayout(entry: entry)
        @unknown default: SimplifiedLayout(entry: entry)
        }
    }
}

审查清单

安装方式和质感
  • 如果小组件应呈现凹陷效果或支持两种效果,需明确设置安装样式
  • 对于包含丰富图像的小组件,将质感设为 .paper
  • 在凸起和凹陷位置均测试小组件(如果两者都支持)
  • 布局在用户将尺寸从模板大小的 75% 调整到 125% 后仍能正常显示
距离感知
  • @Environment(\.levelOfDetail) 为远处的观看者提供简化布局
  • .simplified 布局使用更大的文字、更少的元素和高对比度视觉效果
  • levelOfDetail 的 switch 中包含 @unknown default 分支
类型和布局
  • 在多平台目标中,使用 #if os(visionOS) 限制 .systemExtraLargePortrait
  • 小组件内容可适配每种受支持的类型尺寸
  • 通过 Xcode 预览测试所有已声明的类型尺寸
背景和渲染
  • 使用 .containerBackground(for: .widget) { } 标记可移除的背景
  • 小组件在全彩和强调模式下均能正确渲染
  • 如果前景色取决于背景,需检查 showsWidgetContainerBackground
  • 使用系统语义颜色,确保与玻璃质感兼容
  • 确保前景在全部 7 种浅色和 7 种深色边框着色调色板下均清晰可读

参考资料

评论

支持 Markdown