布局 API
Stack、ScrollView、List/Form、Grid 和 GeometryReader。
本页查 Stack、ScrollView、List/Form、Grid、GeometryReader 和数据展示容器的签名。怎么选择布局结构见 布局系统。
#分篇速查
| 分篇 | 适合查询 |
|---|---|
| 堆叠布局 API | VStack、HStack、ZStack、LazyVStack、LazyHStack、Spacer、Divider。 |
| 滚动 API | ScrollView、ScrollViewReader、滚动方向、初始定位和锚点。 |
| 网格 API | LazyVGrid、LazyHGrid、Grid、GridRow、flexible、fixed、adaptive、grid_item。 |
| 几何与特殊布局 API | GeometryReader、ViewThatFits、Group、Overlay、SafeAreaInset。 |
| 环境值 API | environment_value、preferred_color_scheme、locale、layout_direction、动态字体和文本环境。 |
#什么时候用
| 目标 | API |
|---|---|
| 纵向/横向组合 | VStack、HStack |
| 层叠覆盖 | ZStack、Overlay |
| 自定义滚动内容 | ScrollView、LazyVStack |
| 程序化滚动 | ScrollViewReader |
| 卡片网格 | LazyVGrid、LazyHGrid、Grid |
| 原生动态列表 | List、ForEach |
| 设置和编辑页 | Form、Section |
| 空状态和进度 | ContentUnavailableView、ProgressView |
| 大屏表格 | Table |
#容器组合示例
同一页面可以同时使用 Form、List、LazyVGrid,但要让每个容器负责自己擅长的结构。
已复制
import appui
cards = [
{"id": "a", "title": "Alpha"},
{"id": "b", "title": "Beta"},
{"id": "c", "title": "Gamma"},
]
def card_key(item):
return item["id"]
def card_view(item):
return (
appui.Text(item["title"])
.frame(max_width=appui.infinity, min_height=72)
.background("secondarySystemBackground", corner_radius=8)
)
def body():
grid = appui.LazyVGrid(
columns=[appui.adaptive(minimum=120)],
spacing=12,
content=[appui.ForEach(cards, row_builder=card_view, key=card_key)],
)
return appui.NavigationStack(
appui.Form([
appui.Section("Form", [
appui.LabeledContent("Container", value="Form"),
]),
appui.Section("Grid", [
grid,
]),
]).navigation_title("Layout")
)
appui.run(body)
#布局签名
| API | 签名 | 分类 |
|---|---|---|
VStack | VStack(content: Optional[Sequence[View]] = None, alignment: str = 'center', spacing: Optional[float] = None) | layout |
HStack | HStack(content: Optional[Sequence[View]] = None, alignment: str = 'center', spacing: Optional[float] = None) | layout |
ZStack | ZStack(content: Optional[Sequence[View]] = None, alignment: str = 'center') | layout |
LazyVStack | LazyVStack(content: Optional[Sequence[View]] = None, alignment: str = 'center', spacing: Optional[float] = None) | layout |
LazyHStack | LazyHStack(content: Optional[Sequence[View]] = None, alignment: str = 'center', spacing: Optional[float] = None) | layout |
ScrollView | ScrollView(content: Optional[ViewChild] = None, axes: str = 'vertical', shows_indicators: bool = True, showsIndicators: Optional[bool] = None) | layout |
ScrollViewReader | ScrollViewReader(content: Optional[ViewChild] = None, axes: str = 'vertical', shows_indicators: bool = True, scroll_to: Optional[str] = None, anchor: str = 'top', showsIndicators: Optional[bool] = None, scrollTo: Optional[str] = None, children: Optional[ViewChild] = None) | layout |
LazyVGrid | LazyVGrid(columns: Optional[Sequence[dict]] = None, content: Optional[Sequence[View]] = None, spacing: Optional[float] = None, children: Optional[Sequence[View]] = None) | layout |
LazyHGrid | LazyHGrid(rows: Optional[Sequence[dict]] = None, content: Optional[Sequence[View]] = None, spacing: Optional[float] = None, children: Optional[Sequence[View]] = None) | layout |
Grid | Grid(content: Optional[Sequence[View]] = None, alignment: str = 'center', horizontal_spacing: Optional[float] = None, vertical_spacing: Optional[float] = None, horizontalSpacing: Optional[float] = None, verticalSpacing: Optional[float] = None) | layout |
GridRow | GridRow(content: Optional[Sequence[View]] = None, alignment: Optional[str] = None) | layout |
GeometryReader | GeometryReader(content: Optional[ViewChild] = None, on_change: Optional[Callable] = None, onChange: Optional[Callable] = None, children: Optional[ViewChild] = None, on_geometry: Optional[Callable] = None, onGeometry: Optional[Callable] = None) | layout |
ViewThatFits | ViewThatFits(content: Optional[Sequence[View]] = None) | layout |
Group | Group(content: Optional[Sequence[View]] = None) | layout |
Overlay | Overlay(content: Optional[View] = None, overlay: Optional[View] = None, alignment: str = 'center') | layout |
SafeAreaInset | SafeAreaInset(edge: str = 'bottom', content: Optional[View] = None) | layout |
Spacer | Spacer(min_length: Optional[float] = None, minLength: Optional[float] = None) | layout |
Divider | Divider() | layout |
#数据容器
| API | 签名 | 分类 |
|---|---|---|
List | List(content: Optional[Sequence[View]] = None) | collection |
ForEach | ForEach(data: Any, row_builder: Optional[Callable] = None, key: Optional[Callable] = None, rowBuilder: Optional[Callable] = None, content: Optional[Callable] = None) | collection |
Form | Form(content: Optional[Sequence[View]] = None) | collection |
Section | Section(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 |
GroupBox | GroupBox(label: Optional[str] = None, content: Optional[ViewChild] = None, children: Optional[Sequence[View]] = None) | collection |
DisclosureGroup | DisclosureGroup(label: str = '', is_expanded: Optional[bool] = None, content: Optional[ViewChild] = None, isExpanded: Optional[bool] = None, children: Optional[ViewChild] = None) | collection |
LabeledContent | LabeledContent(label: str = '', value: Optional[str] = None, content: Optional[View] = None) | collection |
Table | Table(data: Optional[Sequence[Dict[str, Any]]] = None, columns: Optional[Sequence[Dict[str, str]]] = None, on_select: Optional[Callable] = None, onSelect: Optional[Callable] = None) | collection |
ControlGroup | ControlGroup(label: str = '', content: Optional[Sequence[View]] = None, children: Optional[Sequence[View]] = None) | control |
ContentUnavailableView | ContentUnavailableView(title: str = '', system_image: Optional[str] = None, description: Optional[str] = None, systemImage: Optional[str] = None) | presentation |
ProgressView | ProgressView(label: Optional[str] = None, value: Optional[float] = None, total: float = 1.0) | feedback |
Link | Link(title: str = '', url: str = '') | control |
Gauge | Gauge(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 |
ShareLink | ShareLink(item: str = '', subject: Optional[str] = None, message: Optional[str] = None) | control |
Badge | Badge(count: Optional[int] = None, text: Optional[str] = None) | presentation |
TimelineView | TimelineView(interval: float = 1.0, content: Optional[View] = None) | feedback |
#相邻 API 区别
| API | 用法边界 |
|---|---|
List vs ScrollView | 动态行列表用 List;完全自定义滚动视觉才用 ScrollView。 |
Form vs VStack | 设置和编辑页用 Form;普通局部排列用 VStack。 |
LazyVGrid vs Grid | 卡片网格用 LazyVGrid;需要严格行列对齐用 Grid。 |
Overlay vs .overlay(...) | 简单叠加优先用修饰符;需要显式节点时用 Overlay。 |
ContentUnavailableView vs 空 Text | 空状态用 ContentUnavailableView,不要让列表区域空白。 |
#常见错误
| 错误 | 后果 | 修正 |
|---|---|---|
VStack(children=[...]) | 构造参数不匹配 | VStack([...], spacing=...)。 |
Section(content=List(...)) | 嵌套滚动容器 | List([Section("Title", rows)])。 |
| 动态列表没有 key | 搜索、删除后行身份不稳 | ForEach(data, row_builder=..., key=...)。 |
| 用自绘卡片模拟设置页 | 信息密度低,键盘和辅助功能差 | Form + Section。 |
| 把重型媒体放进列表行 | 滚动后可能空白或状态丢失 | 媒体放稳定区域,控制项放 Form/List。 |