appui
用 Python 编写原生 MiniApp 页面、状态、导航和交互。
appui 是 PythonIDE 用来编写原生 MiniApp 界面的模块。你用 Python 描述页面结构、状态和交互,PythonIDE 负责把它显示成 iOS 风格的表单、列表、导航、弹层、媒体和图表界面。
#最小脚本
已复制
import appui
state = appui.State(count=0)
def add_one():
state.count += 1
def body():
return appui.NavigationStack(
appui.Form([
appui.Section("计数器", [
appui.LabeledContent("当前值", value=str(state.count)),
appui.Button("加 1", action=add_one)
.button_style("bordered_prominent"),
])
]).navigation_title("AppUI")
)
appui.run(body, state=state)
预期效果:预览打开一个原生表单页面,点击按钮后当前值立即更新。
#先选写法
| 目标 | 推荐看 |
|---|---|
| 第一次写 MiniApp | 快速上手 |
| 判断该用 AppUI、widget、ui 还是 scene | 运行时选择 |
| 选择页面结构 | AppUI UI 模式 |
| 按任务查 API | AppUI API 地图 |
| 排查空白、按钮、输入、列表和权限问题 | MiniApp 开发排错 |
| 查完整函数和组件 | 函数参考 |
#写 AppUI 的心智模型
- 入口:脚本末尾调用一次
appui.run(body, state=state)。 - 页面:
body()或body(view_state)返回一个 AppUI View。 - 状态:
State保存普通界面数据,ReactiveState只用于高频变化。 - 绑定:
Binding/bind()/State.bind()适合输入控件和状态双向连接。 - 结构:设置页用
Form + Section,列表页用List + ForEach,多页面用NavigationStack或TabView。 - 交互:按钮、输入、搜索、刷新和弹层使用命名回调修改状态。
- 副作用:联网、文件、权限、通知和耗时任务不要写在
body()里。
#适用场景
| 需求 | 首选 |
|---|---|
| 表单、设置、列表、详情、工具页 | appui |
| 多页面 MiniApp、Tab、弹层、搜索、刷新 | appui |
| 图表、媒体、地图、WebView 和系统能力入口 | appui + 对应模块 |
| 主屏、锁屏、StandBy 小组件 | widget |
| Sprite、碰撞、逐帧绘制、小游戏 | scene |
| Pythonista 兼容的命令式界面脚本 | ui |
| 纯输出、批处理、日志转换 | 普通 Python / console |
#行为契约
| API | 保证 | 注意 |
|---|---|---|
appui.run(...) | 启动一个 MiniApp 预览或页面。 | 放在脚本末尾,一个脚本只保留一个入口。 |
appui.run(..., presentation=...) | 控制界面呈现方式。 | 可选 'sheet'(默认)、'fullscreen'、'fullscreen_with_close'。 |
State | 字段变化后触发页面重建。 | 多字段同时更新优先用 batch_update(...)。 |
ReactiveState | 适合高频数据更新。 | 普通表单和列表不要默认使用。 |
body() | 描述当前界面。 | 不要在里面发请求、申请权限、写文件或修改状态。 |
Button(action=...) | 点击后执行命名回调。 | 传函数本身,不要写 action=save()。 |
ForEach(..., key=...) | 用稳定 key 维护动态行身份。 | 不要把可变化的 index 当 key。 |
#API 参考
#失败路径
- 预览空白:确认
body()返回 AppUI View,脚本末尾调用了appui.run(...)。 - 按钮没反应:确认
action传入命名函数,而不是函数调用结果。 - 输入不更新:确认
on_change接收新值并写回State。 - 列表错行:确认
ForEach使用稳定key。 - 页面不像原生设置:设置页优先用
Form + Section,不要用一组自绘卡片模拟。 - 权限或网络反复弹出:确认副作用没有写进
body()。
#模块兼容性
appui 与 ui 有 View、Button、TextField、Slider、Image、ScrollView 等同名类/函数,但语义不同。不要在同一文件中同时 from appui import * 和 from ui import *。
appui 与 scene 只有 run 这个入口名容易混淆。混用时用模块名限定调用:appui.run(body) / scene.run(MyScene())。