PythonIDE Docs
中文
简体中文

控件 API

Button、TextField、Toggle、Picker、Slider 等控件签名。

本页是 Text、输入控件、选择控件、按钮和系统控件的参考。这里的示例都使用命名函数连接 action / on_change / on_submit,这样预览打开后可以确认按钮、输入和选择是否真的改变状态。

#什么时候用

目标首选 API说明
普通文字Text静态标签、标题、说明文字。
一段文字混排AttributedText同一段内需要不同颜色、字重、斜体或链接。
执行动作Button保存、删除、刷新、打开页面等命令。
顶层关闭CloseButtonMiniApp 自定义关闭入口,尤其是 fullscreen_with_close
单行输入TextField / SecureField普通文本或密码输入。
多行编辑TextEditor备注、正文、长文本。
搜索.searchable(...)SearchField列表页优先用 .searchable;独立搜索框用 SearchField
布尔开关Toggle开启/关闭某个选项。
数值调节Slider / Stepper连续值用 Slider,离散整数用 Stepper
单选Picker / SegmentedControl / WheelPicker设置项用 Picker,少量模式切换用 SegmentedControl
日期和颜色DatePicker / MultiDatePicker / ColorPicker使用系统原生选择器。
菜单和系统按钮Menu / PasteButton / RenameButton / EditButton复用系统语义和平台样式。

#最小正确示例

python
import appui

state = appui.State(
    name="Ada",
    enabled=True,
    level=3,
    theme="System",
    note="",
)


def set_name(value):
    state.name = value


def set_enabled(value):
    state.enabled = value


def set_level(value):
    state.level = value


def set_theme(value):
    state.theme = value


def set_note(value):
    state.note = value


def reset_controls():
    state.batch_update(
        name="Ada",
        enabled=True,
        level=3,
        theme="System",
        note="",
    )


def body():
    return appui.NavigationStack(
        appui.Form([
            appui.Section("输入", [
                appui.TextField(
                    "Name",
                    text=state.name,
                    on_change=set_name,
                    submit_label="done",
                ),
                appui.TextEditor(text=state.note, on_change=set_note)
                    .frame(height=80),
                appui.Toggle("Enabled", is_on=state.enabled, on_change=set_enabled),
            ]),
            appui.Section("选择", [
                appui.Slider(
                    value=state.level,
                    minimum=0,
                    maximum=10,
                    step=1,
                    label=f"Level {state.level}",
                    on_change=set_level,
                ),
                appui.Picker(
                    "Theme",
                    selection=state.theme,
                    options=["System", "Light", "Dark"],
                    on_change=set_theme,
                ).picker_style("segmented"),
            ]),
            appui.Section("动作", [
                appui.Button("Reset", action=reset_controls)
                    .button_style("bordered"),
            ]),
        ]).navigation_title("Controls")
    )


appui.run(body, state=state)

#文本和按钮

API签名分类
TextText(content: str = '')text
AttributedTextAttributedText(spans: Optional[Sequence[Dict[str, Any]]] = None)text
ButtonButton(title: Optional[Union[str, View]] = None, action: Optional[Callable] = None, role: Optional[str] = None, content: Optional[ViewChild] = None, system_image: Optional[str] = None, image: Optional[str] = None, systemImage: Optional[str] = None)control
CloseButtonCloseButton(title: str = '', system_image: str = 'xmark', systemImage: Optional[str] = None)control
python
import appui


def close_page():
    appui.dismiss()


def body():
    return appui.NavigationStack(
        appui.VStack([
            appui.Text("Plain Text").font("headline"),
            appui.AttributedText(spans=[
                {"text": "Rich ", "font_size": 18},
                {"text": "Text", "font_size": 18, "weight": "bold", "color": "systemBlue"},
                {"text": " link", "italic": True, "link": "https://www.python.org"},
            ]),
            appui.Button(
                appui.Label("Close", system_image="xmark.circle"),
                action=close_page,
            ).button_style("bordered"),
        ], alignment="leading", spacing=12)
        .padding()
        .navigation_title("Text")
    )


appui.run(body)

#输入控件

API签名分类
TextFieldTextField(placeholder: str = '', text: str = '', on_change: Optional[Callable] = None, on_submit: Optional[Callable] = None, keyboard_type: Optional[str] = None, autocapitalization: Optional[str] = None, autocorrection_disabled: bool = False, submit_label: Optional[str] = None, onChange: Optional[Callable] = None, onSubmit: Optional[Callable] = None, keyboardType: Optional[str] = None, autoCapitalization: Optional[str] = None, autocorrectionDisabled: Optional[bool] = None, submitLabel: Optional[str] = None, value: Optional[str] = None, **kwargs: Any)control
SecureFieldSecureField(placeholder: str = '', text: str = '', on_change: Optional[Callable] = None, on_submit: Optional[Callable] = None, onChange: Optional[Callable] = None, onSubmit: Optional[Callable] = None)control
TextEditorTextEditor(text: str = '', on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control
TextFieldLinkTextFieldLink(title: str = '', prompt: str = '', on_submit: Optional[Callable] = None, onSubmit: Optional[Callable] = None)control
SearchFieldSearchField(text: str = '', placeholder: str = 'Search', on_change: Optional[Callable] = None, onChange: Optional[Callable] = None, on_submit: Optional[Callable] = None, onSubmit: Optional[Callable] = None)control

keyboard_type 常用值:"default""emailAddress""numberPad""decimalPad""url""phonePad"submit_label 常用值:"done""go""send""search""next""continue""return"

#选择和调节控件

API签名分类
ToggleToggle(label: str = '', is_on: bool = False, on_change: Optional[Callable] = None, isOn: Optional[bool] = None, onChange: Optional[Callable] = None, value: Optional[bool] = None)control
SliderSlider(value: float = 0.0, minimum: float = 0.0, maximum: float = 1.0, step: Optional[float] = None, label: str = '', on_change: Optional[Callable] = None, onChange: Optional[Callable] = None, min_value: Optional[float] = None, max_value: Optional[float] = None, minValue: Optional[float] = None, maxValue: Optional[float] = None)control
StepperStepper(label: str = '', value: int = 0, minimum: int = 0, maximum: int = 100, step: int = 1, on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control
PickerPicker(label: str = '', selection: Optional[str] = None, options: Optional[Sequence[str]] = None, on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control
SegmentedControlSegmentedControl(options: Optional[Sequence[str]] = None, selection: Optional[str] = None, on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control
InlinePickerStyleInlinePickerStyle(options: Optional[Sequence[str]] = None, selection: Optional[str] = None, on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control
WheelPickerWheelPicker(options: Optional[Sequence[str]] = None, selection: Optional[str] = None, on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control
DatePickerDatePicker(label: str = '', selection: Optional[str] = None, components: str = 'date', on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control
MultiDatePickerMultiDatePicker(title: str = '', on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control
ColorPickerColorPicker(label: str = '', selection: Optional[str] = None, on_change: Optional[Callable] = None, onChange: Optional[Callable] = None)control

#系统控件

API签名分类
MenuMenu(title: str = '', content: Optional[Sequence[View]] = None, children: Optional[Sequence[View]] = None, system_image: Optional[str] = None, image: Optional[str] = None, systemImage: Optional[str] = None)control
PasteButtonPasteButton(on_paste: Optional[Callable] = None, onPaste: Optional[Callable] = None)control
RenameButtonRenameButton(action: Optional[Callable] = None)control
EditButtonEditButton()control
SignInWithAppleButtonSignInWithAppleButton(type: str = 'signIn', on_complete: Optional[Callable] = None, onComplete: Optional[Callable] = None)control

#按钮与菜单的图标

ButtonMenu 都支持直接传 system_image(SF Symbol 名)来显示图标,无需再包一层 content=appui.Label(...)

  • 同时给 titlesystem_image → 图标 + 文字;只给 system_image → 纯图标。
  • Menusystem_image 可以做工具栏右上角的「ellipsis.circle 溢出菜单」。
  • 仍可用 content= 传任意视图作为完全自定义的标签;content 优先级高于 system_image
python
import appui


def noop():
    pass


def body():
    return appui.NavigationStack(
        appui.VStack([
            appui.Button("收藏", action=noop, system_image="bookmark"),
            appui.Button(action=noop, system_image="arrow.clockwise"),
        ], alignment="leading", spacing=12)
        .padding()
        .navigation_title("Icons")
        .toolbar([
            appui.ToolbarItem(
                placement="navigation_bar_trailing",
                content=appui.Menu(system_image="ellipsis.circle", content=[
                    appui.Button("全部", action=noop, system_image="checkmark"),
                    appui.Button("收藏", action=noop),
                ]),
            ),
        ])
    )


appui.run(body)

#与相邻 API 的区别

API不同点
TextField vs TextEditorTextField 是单行输入,支持提交键;TextEditor 是多行编辑区域,通常需要明确 .frame(height=...)
SearchField vs .searchable(...)SearchField 是普通视图;.searchable(...) 会接入导航栏搜索体验,列表页更自然。
Picker vs SegmentedControlPicker 可切换不同样式;SegmentedControl 是固定分段控件,适合少量模式。
Slider vs StepperSlider 适合连续数值;Stepper 适合精确整数或固定步进。
Button vs MenuButton 立即执行单个动作;Menu 先展开命令列表。
Button vs CloseButtonCloseButton 带关闭语义,系统可以识别并避免重复注入关闭按钮。

#常见错误

错误正确做法
在示例里写内联匿名回调,预览里很难读也不利于复用。定义命名函数,例如 def save(): ...,再传 action=save
TextField 只传 text=state.name,没有 on_changeon_change(value) 中写回 state.name = value
Slider 没有设置 minimum / maximum,默认范围和业务不一致。显式写清范围和 step
TextEditor 不设高度。.frame(height=...) 给多行编辑区域稳定尺寸。

#相关文档

文档用途
状态 APIState.batch_updateReactiveStatebindcomputed
交互指南手势、焦点、键盘、上下文菜单。
示例:设置表单完整 Form、Section、输入控件和 toolbar 示例。