PythonIDE Docs
中文
简体中文

数据展示 API

List、ForEach、Form、Section、Table、ProgressView 等数据展示视图。

本页覆盖列表、表单、分组、表格、空状态、进度、链接、角标、时间刷新和富文本。数据展示页面要优先使用系统结构:列表用 List + Section + ForEach,设置页用 Form + Section,不要用普通 VStack 手写整套表单外观。

#什么时候用

目标首选 API说明
行列表List + ForEach可滚动、可分组、可加滑动操作。
设置页Form + Section原生设置样式,适合输入控件和开关。
标题分组Section用 header / footer 表达分组标题和说明。
折叠内容DisclosureGroup可展开详情、更多设置。
标签值行LabeledContent版本号、状态、统计值。
多列表格TableiPad 或大屏数据表;iPhone 会按系统能力降级。
空状态ContentUnavailableView无数据、无搜索结果、加载失败。
进度ProgressView / Gauge加载状态、百分比、容量。
链接和分享Link / ShareLink打开系统浏览器或分享面板。
周期刷新文字TimelineView时钟、倒计时等低频时间展示。
富文本AttributedText同一段文本内混合颜色、字重、斜体和链接。

#最小正确示例

python
import appui

state = appui.State(
    items=[
        {"id": "a", "title": "Alpha", "done": False},
        {"id": "b", "title": "Beta", "done": True},
    ],
    selected="",
)


def item_key(item):
    return item["id"]


def select_item(item):
    state.selected = item["title"]


def row_view(item):
    def choose():
        select_item(item)

    icon = "checkmark.circle.fill" if item["done"] else "circle"
    return appui.Button(
        action=choose,
        content=appui.Label(item["title"], system_image=icon),
    )


def body():
    return appui.NavigationStack(
        appui.List([
            appui.Section("Items", [
                appui.ForEach(state.items, row_builder=row_view, key=item_key)
            ]),
            appui.Section("Selection", [
                appui.LabeledContent("Selected", value=state.selected or "None"),
            ]),
        ]).navigation_title("Data")
    )


appui.run(body, state=state)

#列表和表单

API签名分类
ListList(content: Optional[Sequence[View]] = None)collection
ForEachForEach(data: Any, row_builder: Optional[Callable] = None, key: Optional[Callable] = None, rowBuilder: Optional[Callable] = None, content: Optional[Callable] = None)collection
FormForm(content: Optional[Sequence[View]] = None)collection
SectionSection(content: Optional[ViewChild] = None, *, header: Optional[Union[str, View]] = None, footer: Optional[Union[str, View]] = None, children: Optional[ViewChild] = None, key: Optional[str] = None)collection
python
import appui

state = appui.State(notify=True, email="ada@example.com")


def set_notify(value):
    state.notify = value


def set_email(value):
    state.email = value


def body():
    return appui.NavigationStack(
        appui.Form([
            appui.Section("Account", [
                appui.TextField(
                    "Email",
                    text=state.email,
                    on_change=set_email,
                    keyboard_type="emailAddress",
                ),
                appui.Toggle("Notifications", is_on=state.notify, on_change=set_notify),
            ], footer="Used for account notifications."),
        ]).navigation_title("Form")
    )


appui.run(body, state=state)

#分组和详情

API签名分类
GroupBoxGroupBox(label: Optional[str] = None, content: Optional[ViewChild] = None, children: Optional[Sequence[View]] = None)collection
DisclosureGroupDisclosureGroup(label: str = '', is_expanded: Optional[bool] = None, content: Optional[ViewChild] = None, isExpanded: Optional[bool] = None, children: Optional[ViewChild] = None)collection
LabeledContentLabeledContent(label: str = '', value: Optional[str] = None, content: Optional[View] = None)collection
ControlGroupControlGroup(label: str = '', content: Optional[Sequence[View]] = None, children: Optional[Sequence[View]] = None)control
python
import appui


def body():
    return appui.NavigationStack(
        appui.Form([
            appui.Section("Summary", [
                appui.LabeledContent("Version", value="1.0"),
                appui.LabeledContent("Status", content=appui.Badge(text="New")),
            ]),
            appui.Section("Details", [
                appui.DisclosureGroup(
                    "Advanced",
                    is_expanded=False,
                    content=[
                        appui.GroupBox(
                            "Cache",
                            content=[appui.Text("Local cache is enabled.")],
                        )
                    ],
                )
            ]),
        ]).navigation_title("Groups")
    )


appui.run(body)

#表格

Table(data=None, columns=None, on_select=None, onSelect=None)

参数类型说明
datalist[dict]表格行。
columnslist[dict]每列字典至少包含 titlekey
on_selectCallable / None选中行回调,接收行字典。
python
import appui

state = appui.State(selected="")
rows = [
    {"id": 1, "name": "Ada", "role": "Admin"},
    {"id": 2, "name": "Lin", "role": "Editor"},
]


def select_row(row):
    state.selected = row["name"]


def body():
    return appui.NavigationStack(
        appui.VStack([
            appui.Table(
                data=rows,
                columns=[
                    {"title": "ID", "key": "id"},
                    {"title": "Name", "key": "name"},
                    {"title": "Role", "key": "role"},
                ],
                on_select=select_row,
            ),
            appui.Text(state.selected or "No selection")
                .font("footnote")
                .foreground_color("secondaryLabel"),
        ], spacing=12)
        .padding()
        .navigation_title("Table")
    )


appui.run(body, state=state)

#空状态、进度、链接和分享

API签名分类
ContentUnavailableViewContentUnavailableView(title: str = '', system_image: Optional[str] = None, description: Optional[str] = None, systemImage: Optional[str] = None)presentation
ProgressViewProgressView(label: Optional[str] = None, value: Optional[float] = None, total: float = 1.0)feedback
LinkLink(title: str = '', url: str = '')control
GaugeGauge(value: float = 0.0, min_value: float = 0.0, max_value: float = 1.0, label: str = '', minValue: Optional[float] = None, maxValue: Optional[float] = None)feedback
ShareLinkShareLink(item: str = '', subject: Optional[str] = None, message: Optional[str] = None)control
BadgeBadge(count: Optional[int] = None, text: Optional[str] = None)presentation
python
import appui


def body():
    return appui.NavigationStack(
        appui.List([
            appui.Section("Status", [
                appui.ProgressView(label="Loading"),
                appui.ProgressView(label="Progress", value=0.4, total=1.0)
                    .progress_view_style("linear"),
                appui.Gauge(value=0.72, min_value=0.0, max_value=1.0, label="Storage")
                    .gauge_style("accessory_circular"),
            ]),
            appui.Section("Links", [
                appui.Link(title="Apple", url="https://www.apple.com"),
                appui.ShareLink(item="Shared from AppUI", subject="AppUI", message="Hello"),
            ]),
            appui.Section("Empty", [
                appui.ContentUnavailableView(
                    title="No Results",
                    system_image="magnifyingglass",
                    description="Try another keyword.",
                ),
            ]),
        ]).navigation_title("Status")
    )


appui.run(body)

#TimelineView

TimelineView(interval=1.0, content=None) 会按间隔刷新它的子视图,适合时钟、轻量倒计时等低频时间展示。content 是一个 View,不是视图列表。

python
import appui
import time


def clock_text():
    return appui.Text(time.strftime("%H:%M:%S")).font("title")


def body():
    return appui.NavigationStack(
        appui.TimelineView(interval=1.0, content=clock_text())
        .padding()
        .navigation_title("Clock")
    )


appui.run(body)

#AttributedText

AttributedText(spans=None) 用 span 字典描述富文本。

类型说明
textstr显示文字。
font_sizefloat字号。
weightstr字重,例如 "bold""semibold""regular"
boldbool是否加粗。
italicbool是否斜体。
colorstr颜色,例如 "systemBlue""#FF0000"
linkstr链接 URL。
underlinebool下划线。
strikethroughbool删除线。
python
import appui


def body():
    return appui.NavigationStack(
        appui.AttributedText(spans=[
            {"text": "AppUI ", "font_size": 20, "weight": "bold"},
            {"text": "rich text", "font_size": 20, "color": "systemBlue"},
            {"text": " with link", "link": "https://www.python.org", "underline": True},
        ])
        .padding()
        .navigation_title("Rich Text")
    )


appui.run(body)

#与相邻 API 的区别

API不同点
List vs FormList 展示数据行;Form 展示设置和输入。
Section vs GroupBoxSection 是列表/表单分组;GroupBox 是内容盒。
ProgressView vs GaugeProgressView 强调加载或进度;Gauge 强调数值状态和容量。
Badge vs .badge(...)Badge 是一个独立视图;.badge(...) 给支持角标的位置添加角标。
Link vs WebViewLink 打开外部浏览器;WebView 在 AppUI 内显示网页。
TimelineView vs TimerTimelineView 刷新视图显示;Timer 运行状态更新逻辑。

#常见错误

错误正确做法
ForEach 没有稳定键,列表刷新后行状态错位。key 函数,或保证数据里有稳定 id / key
Section 里再嵌套完整 List外层用一个 List,里面放多个 Section
把设置页写成 VStack + Text + ToggleForm([Section(...)])
TimelineViewcontent 传列表。传一个 View,多视图时包进 VStack
ProgressView(label=appui.Text(...))label 传字符串;自定义说明放在相邻 Text

#相关文档

文档用途
布局 APIVStack、ScrollView、LazyVGrid、Form、List 的布局边界。
呈现 APIrefreshable、swipe actions、context menu。
状态 API让列表和表单响应数据变化。