在 SwiftUI 中,ScrollView 是一个常用的容器,用于显示可以滚动的内容。它非常适合需要展示大量超出屏幕大小的内容时使用,例如垂直或水平列表、图片浏览器等。
ScrollView 的基础结构
ScrollView([轴向], showsIndicators: [布尔值]) {
内容视图
}
参数说明:
1、轴向(Axis.Set):
.vertical:垂直滚动(默认)。
.horizontal:水平滚动。
[.vertical, .horizontal]:支持双向滚动(很少用)。
2、showsIndicators(布尔值,默认为 true):
是否显示滚动条。
3、内容视图:
可以是任意视图类型,通常是动态内容或子视图。
示例代码
1、垂直滚动
struct VerticalScrollView: View {
var body: some View {
ScrollView {
VStack(spacing: 20) { // 使用 VStack 堆叠内容
ForEach(1...30, id: \.self) { index in
Text("Item \(index)")
.padding()
.frame(maxWidth: .infinity)
.background(Color.blue.opacity(0.2))
.cornerRadius(8)
}
}
.padding()
}
}
}
可以通过垂直滚动列表项。

2、水平滚动
struct HorizontalScrollView: View {
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 20) { // 使用 HStack 堆叠内容
ForEach(1...20, id: \.self) { index in
Text("Item \(index)")
.padding()
.frame(width: 150, height: 150)
.background(Color.green.opacity(0.2))
.cornerRadius(8)
}
}
.padding()
}
}
}
可以水平滚动列表项。

3、双向滚动
struct BothDirectionScrollView: View {
var body: some View {
ScrollView([.vertical, .horizontal], showsIndicators: true) {
VStack {
ForEach(1...10, id: \.self) { row in
HStack {
ForEach(1...10, id: \.self) { column in
Text("(\(row), \(column))")
.frame(width: 80, height: 80)
.background(Color.orange.opacity(0.2))
.cornerRadius(8)
}
}
}
}
.padding()
}
}
}
可以水平和垂直双向滚动列表项。

嵌套使用
ScrollView 支持嵌套,但需要注意:
嵌套滚动可能会引发手势冲突,例如内层的滚动行为可能被外层 ScrollView 捕获。
示例:
struct NestedScrollView: View {
var body: some View {
ScrollView {
VStack {
Text("Outer ScrollView")
.font(.title)
.padding()
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(1...10, id: \.self) { index in
Text("Item \(index)")
.padding()
.frame(width: 150, height: 150)
.background(Color.blue.opacity(0.2))
.cornerRadius(8)
}
}
.padding()
}
Text("More content below...")
.padding()
}
}
}
}
可以在多层ScrollView中嵌套。

动态内容适配
LazyVStack 和 LazyHStack
对于大量动态内容,使用 LazyVStack 或 LazyHStack 替代普通的 VStack 和 HStack 可以显著提高性能,因为它们只会渲染屏幕可见的内容。
struct LazyScrollView: View {
var body: some View {
ScrollView {
LazyVStack(spacing: 10) {
ForEach(1...1000, id: \.self) { index in
Text("Row \(index)")
.frame(maxWidth: .infinity)
.padding()
.background(Color.gray.opacity(0.2))
.cornerRadius(8)
}
}
.padding()
}
}
}
LazyVStack和LazyHStack可以通过懒加载实现列表的展示,提高性能。

ScrollViewReader
使用 ScrollViewReader 可以在 ScrollView 中实现滚动到指定位置的功能。
struct ScrollToItemView: View {
var body: some View {
ScrollViewReader { proxy in
ScrollView {
LazyVStack {
ForEach(0..<50, id: \.self) { index in
Text("Row \(index)")
.padding()
.id(index) // 标记每个视图的 ID
}
}
}
.onAppear {
// 滚动到第 25 行
proxy.scrollTo(25, anchor: .center)
}
}
}
}
通过ScrollViewReader可以通过proxy.scrollTo实现,滚动到指定的位置。

注意事项
1、性能优化:
对于大量内容,优先使用 LazyVStack 或 LazyHStack,避免普通 VStack 和 HStack 导致的性能问题。
2、手势冲突:
嵌套 ScrollView 可能引发手势冲突,需要通过 simultaneousGesture 等手段解决。
3、与 GeometryReader 搭配:
ScrollView 常与 GeometryReader 搭配,用于动态效果(如 3D 滚动、渐变等)。
总结
ScrollView 是一个功能强大的容器,用于显示可滚动内容。通过与 LazyVStack、GeometryReader 和 ScrollViewReader 等组件结合,可以实现高效、灵活的滚动视图。
相关文章
SwiftUI容器视图GeometryReader:https://fangjunyu.com/2024/12/15/swiftui%e5%ae%b9%e5%99%a8%e8%a7%86%e5%9b%begeometryreader/