Last active
March 8, 2025 15:35
-
-
Save danwood/2375a89157a9f0f165c6a6223fa0ee62 to your computer and use it in GitHub Desktop.
SwiftUI synchronized ScrollViews — based on code from Phil Zakharchenko's blog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct MultiColumnSyncedScrollDemo: View { | |
let scrollViewCount: Int = 5 | |
@State private var scrollPositions: [ScrollPosition] = [] // Initialized in onAppear, so don't use until body prematurely! | |
@State private var indexScrolledByUser: Int? | |
@State private var colors: [Color] = [] // Initially empty | |
let sampleArrayCount = 40 | |
@ViewBuilder func sampleContent() -> some View { | |
ForEach(1..<sampleArrayCount, id: \.self) { n in | |
Text("\(n)") | |
.frame(width: 160, height: 50) | |
.background(colors.count > 0 ? colors[n] : Color.clear) | |
} | |
} | |
var body: some View { | |
HStack { | |
// This won't show any contents until scrollPositions | |
// has been initialized (with same count as scrollViewCount) | |
ForEach(0..<scrollPositions.count, id: \.self) { thisScrollIndex in | |
ScrollView { | |
sampleContent() | |
} | |
.scrollPosition($scrollPositions[thisScrollIndex]) | |
.onScrollGeometryChange(for: CGFloat.self) { geometry in | |
geometry.contentOffset.y + geometry.contentInsets.top | |
} action: { oldValue, newValue in | |
guard oldValue != newValue else { return } | |
for i in scrollPositions.indices where i != indexScrolledByUser { | |
scrollPositions[i].scrollTo(y: newValue) | |
} | |
} | |
.onScrollPhaseChange { _, newPhase in | |
if newPhase.isScrolling { | |
indexScrolledByUser = thisScrollIndex | |
} | |
} | |
} | |
} | |
.onAppear { | |
scrollPositions = Array(repeating: ScrollPosition(), count: scrollViewCount) | |
for _ in 0..<sampleArrayCount { | |
colors.append(Color.random) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment