ScrollView
Skip support for SwiftUI.ScrollView.
The following example screens and source code is from SkipUI’s
Showcase sample app
ScrollViewPlayground.swift
import SwiftUI
enum ScrollViewPlaygroundType: String, CaseIterable {
case vertical
case horizontal
case readerLazyVStack
case readerLazyHStack
case readerList
case readerStaticList
case readerLazyVGrid
case readerLazyHGrid
var title: String {
switch self {
case .vertical:
return "Vertical"
case .horizontal:
return "Horizontal"
case .readerLazyVStack:
return "ScrollViewReader: LazyVStack"
case .readerLazyHStack:
return "ScrollViewReader: LazyHStack"
case .readerList:
return "ScrollViewReader: ForEach List"
case .readerStaticList:
return "ScrollViewReader: Static List"
case .readerLazyVGrid:
return "ScrollViewReader: LazyVGrid"
case .readerLazyHGrid:
return "ScrollViewReader: LazyHGrid"
}
}
}
struct ScrollViewPlayground: View {
var body: some View {
List(ScrollViewPlaygroundType.allCases, id: \.self) { type in
NavigationLink(type.title, value: type)
}
.toolbar {
PlaygroundSourceLink(file: "ScrollViewPlayground.swift")
}
.navigationDestination(for: ScrollViewPlaygroundType.self) {
switch $0 {
case .vertical:
VerticalScrollViewPlayground()
.navigationTitle($0.title)
case .horizontal:
HorizontalScrollViewPlayground()
.navigationTitle($0.title)
case .readerLazyVStack:
ScrollViewReaderLazyVStackPlayground()
.navigationTitle($0.title)
case .readerLazyHStack:
ScrollViewReaderLazyHStackPlayground()
.navigationTitle($0.title)
case .readerList:
ScrollViewReaderListPlayground()
.navigationTitle($0.title)
case .readerStaticList:
ScrollViewReaderStaticListPlayground()
.navigationTitle($0.title)
case .readerLazyVGrid:
ScrollViewReaderLazyVGridPlayground()
.navigationTitle($0.title)
case .readerLazyHGrid:
ScrollViewReaderLazyHGridPlayground()
.navigationTitle($0.title)
}
}
}
}
private struct VerticalScrollViewPlayground: View {
var body: some View {
ScrollView {
VStack {
ForEach(0..<30) { i in
Text("View: \(i)")
.padding()
}
}
}
}
}
private struct HorizontalScrollViewPlayground: View {
var body: some View {
ScrollView(.horizontal) {
HStack {
ForEach(0..<30) { i in
Text("View: \(i)")
.padding()
}
}
}
}
}
private struct ScrollViewReaderLazyVStackPlayground: View {
var body: some View {
ScrollViewReader { proxy in
VStack(spacing: 16) {
ScrollViewReaderJumpButtons(proxy: proxy)
.padding([.top, .bottom])
ScrollView {
LazyVStack {
ForEach(0..<30, id: \.self) { i in
Text("View: \(i)")
.padding()
}
}
}
.border(.primary, width: 1)
}
}
}
}
private struct ScrollViewReaderLazyHStackPlayground: View {
var body: some View {
ScrollViewReader { proxy in
VStack(spacing: 16) {
ScrollViewReaderJumpButtons(proxy: proxy)
.padding([.top, .bottom])
ScrollView(.horizontal) {
LazyHStack {
ForEach(0..<30, id: \.self) { i in
Text("View: \(i)")
.padding()
}
}
}
.border(.primary, width: 1)
}
}
}
}
private struct ScrollViewReaderListPlayground: View {
var body: some View {
ScrollViewReader { proxy in
VStack(spacing: 16) {
ScrollViewReaderJumpButtons(proxy: proxy)
.padding([.top, .bottom])
List {
Section("Section 0") {
ForEach(0..<10, id: \.self) { i in
Text("View: \(i)")
}
}
Section("Section 1") {
ForEach(10..<20, id: \.self) { i in
Text("View: \(i)")
}
}
Section("Section 2") {
ForEach(20..<30, id: \.self) { i in
Text("View: \(i)")
}
}
}
.border(.primary, width: 1)
}
}
}
}
private struct ScrollViewReaderStaticListPlayground: View {
var body: some View {
ScrollViewReader { proxy in
VStack(spacing: 16) {
ScrollViewReaderJumpButtons(proxy: proxy)
.padding([.top, .bottom])
List {
Section("Section 0") {
Text("View 0")
.id(0)
Text("View 1")
.id(1)
Text("View 2")
.id(2)
Text("View 3")
.id(3)
Text("View 4")
.id(4)
Text("View 5")
.id(5)
Text("View 6")
.id(6)
Text("View 7")
.id(7)
Text("View 8")
.id(8)
Text("View 9")
.id(9)
}
Section("Section 1") {
Text("View 10")
.id(10)
Text("View 11")
.id(11)
Text("View 12")
.id(12)
Text("View 13")
.id(13)
Text("View 14")
.id(14)
Text("View 15")
.id(15)
Text("View 16")
.id(16)
Text("View 17")
.id(17)
Text("View 18")
.id(18)
Text("View 19")
.id(19)
}
Section("Section 2") {
Text("View 20")
.id(20)
Text("View 21")
.id(21)
Text("View 22")
.id(22)
Text("View 23")
.id(23)
Text("View 24")
.id(24)
Text("View 25")
.id(25)
Text("View 26")
.id(26)
Text("View 27")
.id(27)
Text("View 28")
.id(28)
Text("View 29")
.id(29)
}
}
.border(.primary, width: 1)
}
}
}
}
private struct ScrollViewReaderLazyVGridPlayground: View {
var body: some View {
ScrollViewReader { proxy in
VStack(spacing: 16) {
ScrollViewReaderJumpButtons(proxy: proxy)
.padding([.top, .bottom])
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 200))]) {
ForEach(0..<30) { index in
ZStack {
Color.yellow
Text(String(describing: index))
}
.frame(height: 200)
}
}
}
.border(.primary, width: 1)
}
}
}
}
private struct ScrollViewReaderLazyHGridPlayground: View {
var body: some View {
ScrollViewReader { proxy in
VStack(spacing: 16) {
ScrollViewReaderJumpButtons(proxy: proxy)
.padding([.top, .bottom])
ScrollView(.horizontal) {
LazyHGrid(rows: [GridItem(.adaptive(minimum: 200))]) {
ForEach(0..<30) { index in
ZStack {
Color.yellow
Text(String(describing: index))
}
.frame(width: 200)
}
}
}
.border(.primary, width: 1)
}
}
}
}
private struct ScrollViewReaderJumpButtons: View {
let proxy: ScrollViewProxy
var body: some View {
VStack(spacing: 16) {
HStack(spacing: 16) {
Button("Scroll to 0") {
proxy.scrollTo(0)
}
Button("Animated") {
withAnimation { proxy.scrollTo(0) }
}
}
.padding(.top)
HStack(spacing: 16) {
Button("Scroll to 15") {
proxy.scrollTo(15)
}
Button("Animated") {
withAnimation { proxy.scrollTo(15) }
}
}
HStack(spacing: 16) {
Button("Scroll to 29") {
proxy.scrollTo(29)
}
Button("Animated") {
withAnimation { proxy.scrollTo(29) }
}
}
}
}
}