PythonIDE Docs
中文
简体中文

呈现 API

alert、sheet、popover、confirmation dialog 和刷新动作。

本页覆盖弹窗、模态、确认框、菜单、刷新和滑动操作。页面跳转用 导航 API,控件样式和布局修饰符用 修饰符 API

#什么时候用

目标首选 API说明
简短提示.alert(...)单条消息、确认结果、错误提示。
危险操作确认.confirmation_dialog(...)删除、退出、清空等需要用户确认的动作。
局部任务流.sheet(...)选择器、编辑表单、短流程。
全屏任务.full_screen_cover(...)登录、拍摄、沉浸式流程。
iPad 气泡层.popover(...)从某个按钮展开的轻量内容。
长按菜单.context_menu(...)行内次要操作。
下拉刷新.refreshable(...)Refreshable列表重新加载数据。
行滑动操作.swipe_actions(...)SwipeActions删除、归档、置顶等列表行操作。

#最小正确示例

python
import appui

state = appui.State(
    show_sheet=False,
    show_alert=False,
    show_confirm=False,
    count=0,
)


def open_sheet():
    state.show_sheet = True


def close_sheet():
    state.show_sheet = False


def open_alert():
    state.show_alert = True


def close_alert():
    state.show_alert = False


def open_confirm():
    state.show_confirm = True


def close_confirm():
    state.show_confirm = False


def add_count():
    state.count += 1


def reset_count():
    state.count = 0
    state.show_confirm = False


def sheet_content():
    return appui.NavigationStack(
        appui.Form([
            appui.Section("Sheet", [
                appui.Text(f"Count: {state.count}"),
                appui.Button("+1", action=add_count),
                appui.Button("Close", action=close_sheet),
            ])
        ]).navigation_title("Sheet")
    )


def body():
    root = (
        appui.Form([
            appui.Section("Actions", [
                appui.Button("Open sheet", action=open_sheet),
                appui.Button("Show alert", action=open_alert),
                appui.Button("Reset count", action=open_confirm)
                    .foreground_color("systemRed"),
            ])
        ])
        .navigation_title("Presentation")
        .sheet(
            is_presented=state.show_sheet,
            content=sheet_content,
            on_dismiss=close_sheet,
            detents="medium_large",
            drag_indicator="visible",
        )
        .alert(
            "Notice",
            message="Alert is visible.",
            is_presented=state.show_alert,
            on_dismiss=close_alert,
        )
        .confirmation_dialog(
            "Reset count?",
            is_presented=state.show_confirm,
            message="This cannot be undone.",
            actions=[
                appui.Button("Reset", action=reset_count, role="destructive"),
                appui.Button("Cancel", action=close_confirm),
            ],
            on_dismiss=close_confirm,
        )
    )

    return appui.NavigationStack(root)


appui.run(body, state=state)

#呈现组件

这些组件可以作为视图使用;大多数页面更常用对应的链式修饰符。

API签名分类
AlertAlert(title: str = '', message: Optional[str] = None, is_presented: bool = False, actions: Optional[Sequence[View]] = None, isPresented: Optional[bool] = None)presentation
ConfirmationDialogConfirmationDialog(title: str = '', message: Optional[str] = None, is_presented: bool = False, actions: Optional[Sequence[View]] = None, isPresented: Optional[bool] = None)presentation
PopoverPopover(is_presented: bool = False, content: Optional[View] = None, trigger: Optional[View] = None, isPresented: Optional[bool] = None)presentation
RefreshableRefreshable(on_refresh: Optional[Callable] = None, onRefresh: Optional[Callable] = None, content: Optional[ViewChild] = None)collection
SwipeActionsSwipeActions(content: Optional[View] = None, leading: Optional[Sequence[View]] = None, trailing: Optional[Sequence[View]] = None)collection

#呈现修饰符

API签名所属类型
.alert.alert(title: str, message: str = '', is_presented: bool = False, on_dismiss: Optional[Callable] = None, actions: Optional[Sequence["View"]] = None, isPresented: Optional[bool] = None, onDismiss: Optional[Callable] = None) -> SelfView
.sheet.sheet(is_presented: bool = False, content: Optional[Union["View", Callable[[], "View"]]] = None, on_dismiss: Optional[Callable] = None, detents: Optional[str] = None, drag_indicator: Optional[str] = None, interactive_dismiss_disabled: bool = False, isPresented: Optional[bool] = None, onDismiss: Optional[Callable] = None, dragIndicator: Optional[str] = None, interactiveDismissDisabled: Optional[bool] = None) -> SelfView
.full_screen_cover.full_screen_cover(is_presented: bool = False, content: Optional[Union["View", Callable[[], "View"]]] = None, on_dismiss: Optional[Callable] = None, isPresented: Optional[bool] = None, onDismiss: Optional[Callable] = None) -> SelfView
.confirmation_dialog.confirmation_dialog(title: str, is_presented: bool = False, actions: Optional[Sequence["View"]] = None, message: str = '', on_dismiss: Optional[Callable] = None, isPresented: Optional[bool] = None, onDismiss: Optional[Callable] = None) -> SelfView
.popover.popover(is_presented: bool = False, content: Optional[Union["View", Callable[[], "View"]]] = None, on_dismiss: Optional[Callable] = None, isPresented: Optional[bool] = None, onDismiss: Optional[Callable] = None) -> SelfView
.context_menu.context_menu(content: Optional[Sequence["View"]] = None) -> SelfView
.searchable.searchable(text: str = '', on_change: Optional[Callable] = None, onChange: Optional[Callable] = None, placement: str = 'automatic', prompt: Optional[str] = None, on_submit: Optional[Callable] = None, onSubmit: Optional[Callable] = None) -> SelfView
.swipe_actions.swipe_actions(edge: str = 'trailing', content: Optional[Sequence["View"]] = None, actions: Optional[Sequence["View"]] = None) -> SelfView
.refreshable.refreshable(action: Optional[Callable] = None) -> SelfView
.badge.badge(count: Any) -> SelfView
.inspector.inspector(is_presented: bool = False, content: Optional[Union["View", Callable[[], "View"]]] = None, on_dismiss: Optional[Callable] = None) -> SelfView

#列表行操作示例

python
import appui

state = appui.State(items=["Inbox", "Archive", "Later"], last="")


def item_key(item):
    return item


def row_view(item):
    def mark_done():
        state.last = f"Done: {item}"

    def remove_item():
        state.items = [current for current in state.items if current != item]
        state.last = f"Deleted: {item}"

    return (
        appui.Text(item)
        .swipe_actions(actions=[
            appui.Button("Done", action=mark_done),
            appui.Button("Delete", action=remove_item, role="destructive"),
        ])
        .context_menu([
            appui.Button("Mark done", action=mark_done),
        ])
    )


def refresh():
    state.last = "Refreshed"


def body():
    return appui.NavigationStack(
        appui.List([
            appui.Section("Items", [
                appui.ForEach(state.items, row_builder=row_view, key=item_key)
            ]),
            appui.Section("Status", [
                appui.Text(state.last or "No action yet"),
            ]),
        ])
        .navigation_title("Rows")
        .refreshable(refresh)
    )


appui.run(body, state=state)

#与相邻 API 的区别

API不同点
.alert vs .confirmation_dialogalert 用于提示;confirmation dialog 用于让用户在多个操作里确认。
.sheet vs .full_screen_coversheet 适合短任务;full screen 适合必须暂时离开主界面的完整流程。
.popover vs .sheetpopover 更适合 iPad 上从按钮展开的小面板;iPhone 上可能按系统规则表现为 sheet。
.context_menu vs .swipe_actionscontext menu 是次要菜单;swipe actions 是列表行的高频快捷操作。
Refreshable vs .refreshable修饰符更常见;容器用于需要把刷新能力包成独立视图的场景。

#Presentation Engine 规则

  • 呈现修饰符必须始终挂在最终返回的根视图上,只切换 is_presented / show_* 字段。
  • 禁止 if state.show_sheet: root = root.sheet(...) 这种条件挂载。
  • content 传命名函数,例如 content=editor_sheet,不要 content=editor_sheet()
  • 规范全文见 Presentation Engine Spec

#PresentationCoordinator(档 4)

show_* 字段变化时,框架优先走原生 PresentationCoordinator,跳过 body() 与整树 JSON:

python
state.show_sheet = True                 # 自动 coordinator
appui.presentation_present("show_sheet") # 显式 API
appui.presentation_dismiss("show_sheet")
appui.dismiss_all()                   # 关闭所有已注册弹层

混合更新时,presentation 字段先走 coordinator,content 字段仍 rebuild:

python
state.batch_update(show_sheet=True, token_draft="")  # sheet 走 coordinator,draft 走 rebuild

Diagnostics:presentation.coordinator = 快路径;presentation.coordinator_fallback = 回退 JSON。

#常见错误

错误正确做法
sheet 关闭后没有同步 Stateon_dismiss 中把 state.show_sheet = False
sheet 一闪而过,没有原生进出动画。始终挂载 .sheet(is_presented=...),不要条件包裹修饰符。
把复杂业务逻辑直接写在 body() 的按钮参数里。定义命名函数,按钮只传函数名。
alert / dialog 的 is_presented 一直为 True在确认、取消和 dismiss 回调中恢复为 False
列表行删除只改本地变量。修改 State 中的数据源,触发重新渲染。
用 sheet 做顶层页面导航。顶层页面结构用 NavigationStackTabView