PythonIDE Docs
中文
简体中文

widget 资源与外观

渐变/双色背景、accentable 染色、图片/SVG/Symbol、透明与隐私占位。

WidgetKit 负责浅色/深色、透明、系统染色(Tinted)等外观策略。脚本只声明意图——颜色、背景、图标、图片路径——不要用手写遮罩去模拟系统行为。

边界:本篇讲背景、图标、图片、SVG 与 .accentable() 等外观 API。可调默认配色用 widget.param;布局防裁切见 布局与尺寸

#本篇目标

说明
背景纯色、(浅色, 深色)、渐变 dictbackground_image
系统表面container_backgroundtransparent_backgroundcontent_margins
图标w.symbol(SF Symbol)、w.svg(矢量文件)
位图w.imagewidget.param.filewidget.save_image
染色.accentable(True/False) 控制是否参与系统 Tinted
隐私.privacy_sensitive().redacted() 锁屏占位

#快速开始

渐变根背景 + 浅色文字,无需外部图片即可预览。

预期效果:小组件预览面板显示与脚本一致的布局与交互。

python
import widget

w = widget.Widget(
    background={
        "gradient": ["#4F46E5", "#7C3AED", "#DB2777"],
        "direction": "vertical",
    },
    padding=16,
)
with w.row(spacing=10):
    w.symbol("sparkles", scale="medium").color("#FFFFFF")
    w.text("今日灵感", size=16, weight="semibold", color="#FFFFFF").line_limit(1)
w.text("写一段只给自己的话", size=13, color="#E0E7FF").line_limit(2).min_scale(0.72)
w.render()

要点:

  • Widget(background=...) 支持单色、("#F8FAFC", "#0F172A") 双色、或 {"gradient": [...], "direction": "vertical"}
  • 文字颜色可写十六进制或语义名 "secondary"(随系统外观变化)。
  • 渐变方向常用 "vertical" / "horizontal"

#心智模型

text
脚本声明外观意图(颜色 / 背景 / 资源路径 / accentable)
              ↓
    PythonIDE 生成 Widget IR + 资源清单
              ↓
    WidgetKit 按系统外观(浅色 / 深色 / Tinted / 透明)渲染

#背景 API 怎么选

API作用
Widget(background=...)卡片内容区底色(纯色 / 双色 / 渐变)
w.container_background(..., removable=)系统 Widget 容器背景(可请求移除)
w.background_image(...)铺满容器的背景图 + 遮罩
w.transparent_background(True)请求透明(宿主是否允许由系统决定)
w.content_margins(False)边到边布局,去掉系统内容边距

普通卡片用 Widget(background=...);需要照片墙时用 background_image;需要融入主屏壁纸时组合 transparent_background + container_background(..., removable=True)

#资源路径约定

来源写法
脚本同目录"cover.jpg"
assets/ 子目录"assets/icon.svg"
用户文件参数widget.param.file("封面", "assets/cover.jpg", extensions=[...])
运行时注册widget.save_image(url_or_bytes, "avatar")w.image("avatar")
远程 URLw.image("https://example.com/pic.png")(需网络,注意缓存)

深色模式应为图片提供 dark 变体,不要只靠压暗浅色图。


#外观示例

#系统染色(accentable

Tinted / 强调色模式下,只有 .accentable(True) 的节点会跟随系统染色;标题等需保持自定义色时显式 .accentable(False)

预期效果:小组件预览面板显示与脚本一致的布局与交互。

python
import widget

show = widget.param.text("标题", "专注电台")
subtitle = widget.param.text("副标题", "深度工作 · 25 分钟")

w = widget.Widget(background=("#F8FAFC", "#0F172A"), padding=14)
w.container_background(("#F8FAFC", "#0F172A"), removable=True)
w.content_margins(False)
(
    w.text(show, size=16, weight="semibold")
    .line_limit(1)
    .min_scale(0.72)
    .accentable(False)
)
(
    w.text(subtitle, size=12, color="secondary")
    .line_limit(1)
    .min_scale(0.72)
    .accentable(False)
)
(
    w.symbol(
        "waveform.circle.fill",
        rendering="palette",
        palette=["#F59E0B", "#2563EB"],
        variant="fill",
        scale="large",
    )
    .accentable(True)
)
w.render()
  • w.container_background(..., removable=True):允许系统在支持场景移除容器底。
  • w.symbol(..., rendering="palette", palette=[...]):SF Symbol 多色渲染。
  • 图标参与染色 → .accentable(True);文案保持设计色 → .accentable(False)

#分层卡片(layer 背景)

layer 叠一块圆角面板,不必整张 Widget 都上色。

预期效果:小组件预览面板显示与脚本一致的布局与交互。

python
import widget

accent = widget.param.color("面板强调", "#10B981")
task = widget.param.text("待办", "整理发票拍照")

w = widget.Widget(background=("#F1F5F9", "#020617"), padding=14)
w.text("桌面便签", size=14, color="secondary").line_limit(1)
with w.layer(background=("#FFFFFF", "#1E293B"), corner_radius=12, padding=12):
    with w.row(spacing=8):
        w.symbol("checkmark.circle").color(accent).font_size(18)
        w.text(task, size=15, weight="semibold").line_limit(1).min_scale(0.72)
    w.text("下班前完成", size=12, color="secondary").line_limit(1)
w.render()

#图片背景(background_image + 文件参数)

浅色/深色各选一张图;scrim="bottom" 在底部加渐变遮罩,保证白字可读。

预期效果:小组件预览面板显示与脚本一致的布局与交互。

python
import widget

light_bg = widget.param.file("浅色背景", "", extensions=["jpg", "jpeg", "png"])
dark_bg = widget.param.file("深色背景", "", extensions=["jpg", "jpeg", "png"])
title = widget.param.text("标题", "周末登山")

w = widget.Widget(padding=14)
w.background_image(
    (light_bg, dark_bg),
    content_mode="fill",
    focal="center",
    scrim="bottom",
    scrim_opacity=0.48,
)
w.text(title, size=18, weight="bold", color="#FFFFFF").line_limit(1).min_scale(0.72)
w.text("海拔 1280m", size=12, color="#E2E8F0").line_limit(1)
w.render()
  • 预览侧栏用文件参数选图;路径相对于 widget 脚本或项目 assets/
  • focal="topTrailing" 等控制 fill 裁剪焦点;content_mode="fit" 可整张展示不裁剪。

#头像位图(w.image

角标/封面用 w.image;支持圆角与浅色/深色双资源。

预期效果:小组件预览面板显示与脚本一致的布局与交互。

python
import widget

avatar = widget.param.file("头像", "", extensions=["png", "jpg", "jpeg"])
frame = widget.family_value(44, small=36, large=52)

w = widget.Widget(background=("#FFFFFF", "#111827"), padding=14)
with w.row(spacing=12):
    w.image(avatar, width=frame, height=frame, corner_radius=frame / 2, content_mode="fill")
    with w.column(spacing=4):
        w.text("Py 开发者", size=15, weight="semibold").line_limit(1).min_scale(0.72).line_limit(1)
        w.text("本周 commit +12", size=12, color="secondary").line_limit(1)
w.render()

若有两张图,可写 w.image(light="avatar-light.png", dark="avatar-dark.png", ...) 或元组 w.image(("light.png", "dark.png"), ...)

#SVG 图标(w.svg

适合单色可着色的矢量角标;文件放 assets/ 或通过 param.file 选择。

预期效果:小组件预览面板显示与脚本一致的布局与交互。

python
import widget

icon = widget.param.file("图标", "", extensions=["svg"])
accent = widget.param.color("图标色", "#22C55E")
size = widget.family_value(28, small=24, large=32)

w = widget.Widget(background=("#FAFAFA", "#1C1C1E"), padding=14)
with w.row(spacing=10):
    w.svg(icon, width=size, height=size, color=accent, content_mode="fit")
    with w.column(spacing=2):
        w.text("自定义 SVG", size=15, weight="semibold").line_limit(1).min_scale(0.72).line_limit(1)
        w.text("path + viewBox 图标", size=12, color="secondary").line_limit(1)
w.render()

预览侧栏选本地 .svg 文件;简单场景优先 w.symbol(...),免维护文件。

#隐私占位(锁屏敏感信息)

步数等敏感数字在锁屏可模糊;与 时间线和动画numericText 可叠加。

预期效果:小组件预览面板显示与脚本一致的布局与交互。

python
import widget

steps = widget.state.int("steps", 8420)

w = widget.Widget(background=("#F0FDF4", "#14532D"), padding=14)
(
    w.text("今日步数", size=14, color="secondary")
    .line_limit(1)
    .privacy_sensitive()
)
(
    w.value(steps, unit="步")
    .monospaced_digit()
    .line_limit(1)
    .min_scale(0.72)
    .privacy_sensitive()
    .redacted("placeholder")
)
w.text("锁屏显示占位,解锁后见完整数字", size=11, color="secondary").line_limit(1)
w.render()
  • .privacy_sensitive():标记敏感内容。
  • .redacted("placeholder"):锁屏显示系统占位样式。

#透明背景

请求透明需同时声明容器可移除与透明开关;桌面是否真透明取决于宿主与系统。

python
w = widget.Widget(padding=12)
w.transparent_background(True)
w.container_background("clear", removable=True)
w.content_margins(False)
w.text("透明卡片", size=15, weight="semibold").accentable(True)
w.render()

不要在透明卡片上再叠不透明全屏 Widget(background=...),否则透明意图会被盖住。


#API 参考

#背景与容器

python
# 纯色 / 双色 / 渐变
w = widget.Widget(background="#FFFFFF")
w = widget.Widget(background=("#F8FAFC", "#0F172A"))
w = widget.Widget(background={"gradient": ["#3B82F6", "#8B5CF6"], "direction": "horizontal"})

w.background(("#FAFAFA", "#18181B"))          # 运行时改根背景
w.container_background(bg, removable=True)   # 系统容器底
w.transparent_background(True)               # 请求透明
w.content_margins(False)                       # 边到边

w.background_image(
    ("day.jpg", "night.jpg"),
    content_mode="fill",
    scrim="bottom",
    scrim_opacity=0.45,
    focal="center",
)

#图标与图片

python
w.symbol("star.fill", scale="large").color("#F59E0B")
w.symbol("paintpalette.fill", rendering="palette", palette=["#EF4444", "#3B82F6"])

w.svg("assets/logo.svg", width=24, height=24, color="#111827")
w.image("cover.jpg", width=60, height=60, corner_radius=8)
w.image(light="avatar-light.png", dark="avatar-dark.png", rendering_mode="accented")

#外观修饰符

python
w.text("标题").accentable(False)
w.symbol("bell.fill").accentable(True)
w.text("余额").privacy_sensitive().redacted("placeholder")

#运行时保存图片

python
# 脚本中下载或生成后注册,供 w.image / background_image 按名称引用
path = widget.save_image("https://example.com/pic.png", "cover")
w.image("cover", width=80, height=80)

完整签名见 API 参考container_backgroundbackground_imagetransparent_backgroundsymbolsvgimage.accentable.privacy_sensitive.redacted


#常见错误

错误写法后果修正
染色模式下标题变色未关闭 accentable设计色文案 .accentable(False)
图标不跟系统色写了 .accentable(False)应用染色的图标 .accentable(True)
深色模式图片发灰只有浅色图background_image((light, dark))image(light=, dark=)
透明不生效只设了 Widget 底色transparent_background + container_background(removable=True)
SVG 空白路径错或预览无文件assets/ 或用 param.file 重选
背景图字看不清无遮罩scrim="bottom" + scrim_opacity
用手写 rect 模拟系统底与 WidgetKit 策略冲突container_background / transparent_background
w.symbol(..., color=, size=)TypeErrorw.symbol("name").color(c).font_size(n)

#失败路径

现象处理
预览浅色正常、深色异常检查 (light, dark) 是否成对提供
Tinted 模式颜色全乱梳理每个节点的 accentable 默认值与显式设置
图片不显示路径、extensions、是否已 save_image 注册
SVG 构建报错确认是图标级 SVG(viewBox + path);复杂 SVG 可能需简化
锁屏数字太清晰.privacy_sensitive() + .redacted("placeholder")
透明在桌面无效系统/宿主限制;回退半透明双色背景
预览与桌面不一致重新发布;查 排错

#相关文档

文档用途
widget 概览总览
参数面板param.color / param.file
布局与尺寸图标尺寸、family_value
时间线和动画numericText 与隐私数字叠加
排错预览/桌面外观不一致
API 参考完整签名

相关 API:widget-api-reference.md