PythonIDE Docs
中文
简体中文

表格数据审阅

Table、筛选、批量动作和 iPhone fallback。

演示 Table 多列展示与 Picker 在列表模式之间的切换,共用同一数据源。

#预期效果

运行后会出现可筛选的数据审核表,支持选择行、查看摘要,并在窄屏上退化为列表体验。

#适合场景

  • iPad 或横屏下需要多列查看的数据审核页。
  • 手机上需要保留列表模式作为窄屏降级。

#页面结构

区域结构作用
模式切换Picker + segmented在列表和表格之间切换。
列表模式List + ForEach + NavigationLink手机上查看详情。
表格模式TableiPad 上快速扫描多列数据。

#完整示例

python
import appui

state = appui.State(
    mode="列表",
    selected="",
    rows=[
        {"name": "TextField", "area": "输入", "status": "OK", "owner": "Form"},
        {"name": "Slider", "area": "控制", "status": "OK", "owner": "Controls"},
        {"name": "VideoPlayer", "area": "媒体", "status": "观察", "owner": "Media"},
        {"name": "Table", "area": "数据", "status": "iPad 优先", "owner": "Data"},
    ],
)

columns = [
    {"title": "组件", "key": "name"},
    {"title": "区域", "key": "area"},
    {"title": "状态", "key": "status"},
]


def set_mode(value):
    state.mode = value


def select_row(row):
    state.selected = f"{row.get('name', '')} / {row.get('status', '')}"


def row_detail(row):
    return appui.Form(
        [
            appui.Section(
                [
                    appui.LabeledContent("组件", value=row["name"]),
                    appui.LabeledContent("区域", value=row["area"]),
                    appui.LabeledContent("状态", value=row["status"]),
                    appui.LabeledContent("负责人", value=row["owner"]),
                ],
                header="详情",
            )
        ]
    ).navigation_title(row["name"])


def row_key(row):
    return row["name"]


def row_link(row):
    return appui.NavigationLink(
        destination=row_detail(row),
        label=appui.HStack(
            [
                appui.VStack(
                    [
                        appui.Text(row["name"]).font("headline"),
                        appui.Text(row["area"]).font("caption").foreground_color("secondaryLabel"),
                    ],
                    alignment="leading",
                ),
                appui.Spacer(),
                appui.Text(row["status"]).font("caption").foreground_color("systemBlue"),
            ]
        ),
    )


def list_mode():
    return appui.List(
        [
            appui.Section("组件", [
                appui.ForEach(
                    state.rows,
                    row_builder=row_link,
                    key=row_key,
                )
            ])
        ]
    )


def table_mode():
    return appui.VStack(
        [
            appui.Table(data=state.rows, columns=columns, on_select=select_row).frame(height=260),
            appui.Text(state.selected or "点选表格行查看选择结果")
                .font("caption")
                .foreground_color("secondaryLabel"),
        ],
        spacing=12,
    ).padding()


def body():
    content = table_mode() if state.mode == "表格" else list_mode()
    return appui.NavigationStack(
        appui.VStack(
            [
                appui.Picker("显示方式", selection=state.mode, options=["列表", "表格"], on_change=set_mode)
                    .picker_style("segmented")
                    .padding(horizontal=16),
                content,
            ],
            spacing=8,
        ).navigation_title("数据审阅")
    )


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

#关键技巧

  • Tablecolumns 使用 {"title", "key"} 字典列表;data 为字典列表。
  • 手机窄屏可保留「列表」模式;on_select 接收选中行字典。
  • 表格与列表共用纯数据行,不把视图对象放进 state.rows

#失败路径

  • 表格选中后把结果写入 state.selected,否则用户不知道点选是否生效。
  • 如果业务数据为空,列表模式应显示 ContentUnavailableView,表格模式应显示说明文本。

#相关文档

文档用途
数据 APITableForEach 和动态数据。
列表指南列表行身份和空状态。