列表与分区(List and Section)
意图
对于信息流式内容和设置风格的行,使用 List,此时内置的行复用、选择和可访问性很重要。
核心模式
- 对带有重复行的长垂直滚动内容,优先使用 List。
- 使用 Section 标题对相关行分组。
- 需要滚动到顶部或跳转到指定 id 时,配合 ScrollViewReader。
- 对现代信息流布局使用 .listStyle(.plain)。
- 对分区分组有帮助的多分区发现/搜索页,使用 .listStyle(.grouped)。
- 需要主题化表面时,应用 .scrollContentBackground(.hidden) + 自定义背景。
- 使用 .listRowInsets(…) 和 .listRowSeparator(.hidden) 调整行间距和分隔线。
- 使用 .environment(\\\\.defaultMinListRowHeight, …) 控制紧凑列表布局。
示例:带滚动到顶部的信息流列表
@MainActor
struct TimelineListView: View {
@Environment(\\.selectedTabScrollToTop) private var selectedTabScrollToTop
@State private var scrollToId: String?
var body: some View {
ScrollViewReader { proxy in
List {
ForEach(items) { item in
TimelineRow(item: item)
.id(item.id)
.listRowInsets(.init(top: 12, leading: 16, bottom: 6, trailing: 16))
.listRowSeparator(.hidden)
}
}
.listStyle(.plain)
.environment(\\\\.defaultMinListRowHeight, 1)
.onChange(of: scrollToId) { _, newValue in
if let newValue {
proxy.scrollTo(newValue, anchor: .top)
scrollToId = nil
}
}
.onChange(of: selectedTabScrollToTop) { _, newValue in
if newValue == 0 {
withAnimation {
proxy.scrollTo(ScrollToView.Constants.scrollToTop, anchor: .top)
}
}
}
}
}
}
示例:设置风格列表
@MainActor
struct SettingsView: View {
var body: some View {
List {
Section("General") {
NavigationLink("Display") { DisplaySettingsView() }
NavigationLink("Haptics") { HapticsSettingsView() }
}
Section("Account") {
Button("Sign Out", role: .destructive) {}
}
}
.listStyle(.insetGrouped)
}
}
应保留的设计选择
- 对动态信息流、设置以及任何行语义有帮助的 UI 使用 List。
- 为行使用稳定的 ID,以保持动画和滚动定位可靠。
- 对应当整行可点击的行,优先使用 .contentShape(Rectangle())。
- 当数据源支持时,对下拉刷新信息流使用 .refreshable。
陷阱
- 避免在 List 行内使用重型自定义布局;改用 ScrollView + LazyVStack。
- 小心混用 List 和嵌套的 ScrollView;可能导致手势冲突。
网硕互联帮助中心







评论前必须登录!
注册