PythonIDE Docs
中文
简体中文

原生表单设置

Form、Section、输入控件、颜色选择和 storage 持久化。

演示 Form + Section 与各类控件绑定 State,并用 storage 持久化偏好。

#预期效果

运行后会出现完整表单设置页,文本、开关、日期、颜色和保存状态会同步更新。

#完整示例

python
import appui
import haptics
import storage

SETTINGS_KEY = "demo.native.settings"

defaults = {
    "display_name": "MiniApp 用户",
    "api_token": "",
    "mode": "自动",
    "refresh_minutes": 15,
    "volume": 0.55,
    "accent": "systemBlue",
    "deadline": "2026-05-01 09:00",
    "sync_enabled": True,
    "wifi_only": True,
}

state = appui.State(**defaults, status="未保存", loaded=False)


def load_saved_settings():
    if state.loaded:
        return
    state.loaded = True
    saved = storage.get_json(SETTINGS_KEY, default={}) or {}
    for key, fallback in defaults.items():
        setattr(state, key, saved.get(key, fallback))
    if saved:
        state.status = "已加载保存设置"


def update(field):
    def setter(value):
        setattr(state, field, value)
    return setter


def save_settings():
    payload = {
        "display_name": state.display_name,
        "api_token": state.api_token,
        "mode": state.mode,
        "refresh_minutes": int(state.refresh_minutes),
        "volume": float(state.volume),
        "accent": state.accent,
        "deadline": state.deadline,
        "sync_enabled": bool(state.sync_enabled),
        "wifi_only": bool(state.wifi_only),
    }
    storage.set_json(SETTINGS_KEY, payload)
    state.status = "已保存"
    haptics.notification("success")


def reset_settings():
    for key, value in defaults.items():
        setattr(state, key, value)
    state.status = "已恢复默认"
    haptics.notification("warning")


def body():
    return appui.NavigationStack(
        appui.Form(
            [
                appui.Section(
                    [
                        appui.TextField(
                            "显示名称",
                            text=state.display_name,
                            on_change=update("display_name"),
                        ),
                        appui.SecureField(
                            "API Token",
                            text=state.api_token,
                            on_change=update("api_token"),
                        ),
                    ],
                    header="账号",
                    footer="Token 只用于演示表单输入;生产场景请保存到 keychain。",
                ),
                appui.Section(
                    [
                        appui.Toggle(
                            "启用同步",
                            is_on=state.sync_enabled,
                            on_change=update("sync_enabled"),
                        ),
                        appui.Toggle(
                            "仅 Wi-Fi 同步",
                            is_on=state.wifi_only,
                            on_change=update("wifi_only"),
                        ),
                        appui.Picker(
                            "同步模式",
                            selection=state.mode,
                            options=["自动", "手动", "低电量"],
                            on_change=update("mode"),
                        ),
                    ],
                    header="同步",
                ),
                appui.Section(
                    [
                        appui.Stepper(
                            "刷新间隔",
                            value=state.refresh_minutes,
                            minimum=5,
                            maximum=120,
                            step=5,
                            on_change=update("refresh_minutes"),
                        ),
                        appui.LabeledContent("当前间隔", value=f"{int(state.refresh_minutes)} 分钟"),
                        appui.Slider(
                            value=state.volume,
                            minimum=0,
                            maximum=1,
                            step=0.05,
                            label="提示音量",
                            on_change=update("volume"),
                        ),
                        appui.ProgressView(value=state.volume),
                    ],
                    header="数值",
                ),
                appui.Section(
                    [
                        appui.DatePicker(
                            "提醒时间",
                            selection=state.deadline,
                            components="date",
                            on_change=update("deadline"),
                        ),
                        appui.ColorPicker(
                            "强调色",
                            selection=state.accent,
                            on_change=update("accent"),
                        ),
                    ],
                    header="外观与时间",
                ),
                appui.Section(
                    [
                        appui.LabeledContent("状态", value=state.status),
                        (
                            appui.Button("保存设置", action=save_settings)
                            .button_style("bordered_prominent")
                        ),
                        appui.Button("恢复默认", role="destructive", action=reset_settings),
                    ],
                    header="操作",
                ),
            ]
        ).navigation_title("设置")
    ).on_appear(load_saved_settings)


appui.run(body, state=state, presentation="sheet")

#关键技巧

  • 设置页优先 Form + Section;控件值绑定 State 并在 on_change 写回。
  • 一般偏好用 storage;真密钥用 keychain
  • 持久化读取放进 on_appear,不要在模块加载时访问原生存储,预览和首次渲染会更稳定。
  • Toggleon_change 只更新状态,避免顺带做 Tab 切换等导航副作用。