PythonIDE Docs
中文
简体中文

widget 状态和交互

widget.state、按钮 ±、习惯清单、开关与链接;AppIntent 桌面交互。

桌面小组件不执行任意 Python 回调。按钮、开关、列表勾选只能触发受控 AppIntent:改写 widget.state、刷新时间线,或打开链接。

边界:本篇讲桌面点击widget.state。预览面板里的配色、标题默认值用 widget.param,不要混用。

#本篇目标

说明
何时用计数器、完成开关、习惯勾选、打开网页/深链
核心 APIwidget.state.*.increment() / .toggle() / .toggle_item()
节点w.button(..., action=)w.toggle(..., state=)w.link(...)
限制action= 必须来自 state 工厂;不能传 Python 函数
发布后改 state key 需重新发布;桌面可能需删组件重装

#快速开始

单按钮累加 + 数字过渡:比 概览 · 饮水打卡 的 ± 环图更简单,专讲 actionnumericText

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

python
import widget

streak = widget.state.int("streak", 0)
accent = widget.param.color("主色", "#2563EB")

w = widget.Widget(background=("#FFFFFF", "#0F172A"), padding=14)
w.text("连续签到", size=16, weight="semibold").line_limit(1)
(
    w.value(streak, unit="天")
    .id("streak")
    .content_transition("numericText")
    .monospaced_digit()
    .line_limit(1)
    .min_scale(0.72)
)
(
    w.button("签到", action=streak.increment(), background=accent, color="#FFFFFF")
    .line_limit(1)
    .min_scale(0.72)
    .pressed(scale=0.94)
)
w.render()

要点:

  • streak.increment() 返回 AppIntent,赋给 action=不能写字符串或 Python 函数。
  • .content_transition("numericText") + .id(...):数字变化时系统过渡动画。
  • .pressed(scale=0.94) 等价于 button(..., press={"scale": 0.94})
  • widget.param.color 只调配色,不改桌面计数值。

#交互示例

#习惯清单(state.list + toggle_item

多项勾选用 widget.state.list;每项 done.toggle_item(i) 切换是否在列表里。

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

python
import widget

habits = ["晨跑", "喝水 8 杯", "阅读 30 分", "整理桌面"]
done = widget.state.list("habits_done", [])
accent = widget.param.color("完成色", "#22C55E")

w = widget.Widget(background=("#FAFAFA", "#1C1C1E"), padding=14)
w.text("今日习惯", size=16, weight="semibold").line_limit(1)
for i, label in enumerate(habits):
    checked = done.contains(i)
    mark = "✓ " if checked else "○ "
    (
        w.button(
            mark + label,
            action=done.toggle_item(i),
            style="plain",
            color=accent if checked else "secondary",
            size=13,
        )
        .line_limit(1)
        .min_scale(0.72)
    )
w.render()
  • done.contains(i):预览/桌面判断第 i 项是否已勾选;toggle_item(i)i 类型须与 contains 一致。
  • 多项也可用多个 w.toggle(..., state=);长清单用 state.list 更省节点。
  • 九宫格、Bingo 等表格布局见 布局与尺寸table() 示例。

#开关(state.bool + w.toggle

布尔状态用 state= 绑定,不要手写静态 True/False 配假 action。

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

python
import widget

alarm_on = widget.state.bool("alarm_on", False)
accent = widget.param.color("开启色", "#F59E0B")

w = widget.Widget(background=("#FFFBEB", "#292524"), padding=14)
w.text("早起闹钟", size=16, weight="semibold").line_limit(1)
w.toggle("明早 7:00", state=alarm_on, color=accent, style="switch")
# 脚本每次重建时读取 state 当前值(非 AppUI 式实时绑定)
status = "已开启,记得早睡" if alarm_on else "已关闭"
w.text(status, size=13, color=accent if alarm_on else "secondary").line_limit(1).min_scale(0.72)
w.render()
  • w.toggle(..., color=accent):着色用 color=没有 tint= 参数。
  • style="switch" / "checkbox" 控制外观;与 state= 搭配最省事。

链接打开 URL;与按钮/开关不要叠在同一块可点区域

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

python
import widget

label = widget.param.text("链接标题", "Apple 官网")
accent = widget.param.color("链接色", "#2563EB")

w = widget.Widget(background=("#FFFFFF", "#111827"), padding=14)
w.text("快捷入口", size=16, weight="semibold").line_limit(1)
w.link(label, "https://www.apple.com", icon="safari.fill", color=accent)
w.text("点击在 Safari 打开", size=12, color="secondary").line_limit(1).min_scale(0.72)
w.render()
  • 第一参数是显示标题,第二参数是 URL 字符串。
  • 可选 icon= 在标题旁显示 SF Symbol。
  • icon= 时返回行容器,不能链 .line_limit();无 icon 时返回 text 句柄才可链修饰符。
  • 整块链接与局部 button 分清层级;同一容器不要既当链接又塞按钮。

#心智模型

text
widget.state.int/bool/list/...   ← 桌面持久化
        ↓
.increment() / .toggle() / .toggle_item(i)   ← AppIntent 工厂
        ↓
w.button(..., action=...)  或  w.toggle(..., state=...)
        ↓
用户点击 → 扩展执行 Intent → 状态改写 → WidgetKit 刷新时间线
  1. 先声明 state:在 Widget() 构建前,与 widget.param 同级。
  2. action 只接工厂方法count.increment()done.toggle()items.toggle_item(2)
  3. 开关优先 state=w.toggle("标题", state=done),让运行时自动绑 done.toggle()
  4. 链接不走 statew.link(title, url) 直接打开;深链同样写 URL 字符串。
  5. 改 key 要重发"score" 改成 "points" 后,旧桌面实例可能仍读写 "score"

#widget.param 怎么分

widget.paramwidget.state
谁改预览面板 / Studio桌面点击
典型主题色、默认标题计数、开关、清单勾选
传给 UIcolor=background=value / state= + action

#API 参考

#状态类型

API适合常用动作
widget.state.int(key, default)次数、步数、分数.increment(by=1).decrement(by=1).set(n)
widget.state.float(key, default)进度、比例同上
widget.state.bool(key, default)完成、开启.toggle();配合 w.toggle(..., state=)
widget.state.str(key, default)当前模式、选中项.set("模式A")
widget.state.list(key, default)多选清单、Bingo.toggle_item(item).contains(item).set([])

key 是持久化 ID;改名等同新状态,需重新发布。

#交互节点

python
count = widget.state.int("count", 0)
done = widget.state.bool("done", False)
items = widget.state.list("picked", [])

w.button("加 1", action=count.increment())
w.button("减 2", action=count.decrement(by=2))
w.button("归零", action=count.set(0), style="plain")
w.toggle("完成", state=done, color="#22C55E")
w.button("选 A", action=items.toggle_item("A"), style="plain")
w.link("文档", "https://example.com", icon="book.fill")

#动效修饰(可选)

python
w.button("+", action=count.increment()).pressed(scale=0.94)
w.value(count).content_transition("numericText").monospaced_digit()

数字变化动画见 时间线和动画;完整签名见 API 参考


#常见错误

错误写法后果修正
action="increment" 或 Python 函数点击无反应count.increment() 等工厂
w.toggle(..., tint=accent)TypeErrorcolor=accent
静态 True + 手写 toggle action开关不保存w.toggle(..., state=done)
widget.param.bool 当桌面开关只在预览里变交互用 widget.state.bool
链接容器里再塞 button点击区域冲突链接、按钮分块布局
改 state key 不重发计数错乱或归零重新发布;删桌面组件重装

#失败路径

现象处理
按钮点击没反应确认 action 来自 widget.state 工厂方法
Toggle 显示但不记忆改用 state=,勿拼静态布尔
清单勾选无效toggle_item 的参数类型与 contains 一致(都用 int 或都用 str
链接打不开检查 URL 含 https://;勿与按钮叠层
点击后桌面仍旧AppIntent 已执行但 WidgetKit 缓存 → 重新运行发布;删组件重装
预览能点、桌面不能确认已走 从脚本到桌面 发布流程

#相关文档

文档用途
widget 概览总览与入门示例
参数面板widget.param 与 state 区分
从脚本到桌面发布后在桌面验证交互
布局与尺寸table() 九宫格、row() 横排
时间线和动画content_transition、数字过渡
排错预览/桌面不一致
API 参考widget.statebuttontogglelink 签名

相关 API:widget-api-reference.md