A high-performance vertical stack implementation for list-style layouts in SwiftUI.
An alternative to the standard LazyVStack and List, focused on correct layout, improved hitch rate/RAM usage and fine-grained control.
- 📐 Access to container content size information (without using
GeometryReaderor theprotocol Layout) - 🧹 No size's information "spam" to client
- ✅ Correct layout. No "white" flaky screens, no content truncating
- 🪵 Improved cell's rendering OSLogging quality
- ⚡️ Enhanced memory usage performance
- 📥 Clone the repository
- 🧩 Write a bit of code and build the project
OptimizedVStack(
data: $viewModel.items,
spacing: 8,
onChangeOfHeight: {
print($0.formatted)
}
) { index in
CellView(by: $viewModel.items[index])
}- 👀 Observe the height value in the console
👉 Alternatively, you can open the Demo/Screen folder and modify any of the prototypes as you like.
- Fixed row height lists
- Variable row height lists
- Dynamic row height lists
- List pagination
The simplest initialization looks like this:
OptimizedVStack(
data: items
) { index in
CellView(by: items[index])
}- For the "scroll progress tracking" case, the following API is used in the Demo app:
ProgressLine(...)
OptimizedVStack(
data: $viewModel.items,
spacing: 8,
onChangeOfScrollProgress: { currentYMax, measuredheight in
let totalHeight = switch measuredheight {
case .exact(let total), .estimated(let total, _, _):
total
default:
CGFloat.zero
}
viewModel.updateScrollProgress(
currentYMax: currentYMax, totalHeight: totalHeight
)
},
rowContent: { index in
CellView(by: viewModel.items[index])
},
footer: {
loader
}
)- For the "pagination" use case, the following API is used in the Demo app:
OptimizedVStack(
data: $viewModel.items,
spacing: 8,
onChangeOfHeight: {
print($0.formatted)
},
rowContent: { index in
CellView(by: viewModel.items[index])
},
footer: {
loader
}
)The implementation sends content setup logs via OSLog.
Inspired by the native LazyVStack logs, enabled through the UserDefaults key: com.apple.SwiftUI.LazyStackLogging.
Actual content height: 1086
Tested: iOS 26
Test's scheme: link
| Approach | Result | Final Height | Iterations | API Notes |
|---|---|---|---|---|
| List + GeometryReader | - | 778 | - | iOS 13+ |
| List + Introspect + uiCollectionView.contentSize | - | 803 | - | iOS 13+ |
| LazyVStack + GeometryReader | + | 1086 | 5 | iOS 14+ |
| LazyVStack + ViewThatFits | + | 1086 | 5 | iOS 16.4+ |
| LazyVStack + View.scrollBounceBehavior | + | 1086 | 2 | iOS 16.4+ |
| OptimizedVStack + onChangeOfHeight | + | 1086 | 1 | iOS 14+ |
First's frame layout speed
iPhone 12, iOS 18.6.2
Test's scheme: link
| Approach | Result |
|---|---|
| LazyVStack | 25 ms. |
| OptimizedVStack | 10 ms. |
Hitch test (dragging the scroll indicator for fast scrolling in 30 seconds)
iPhone 12, iOS 18.6.2
Test's scheme: link
| Approach | Hitch time | Max hitch |
|---|---|---|
| LazyVStack | 610 ms. | 80 ms. |
| List | 3.5 s. | 75 ms. |
| OptimizedVStack | 315 ms. | 70 ms. |
Peak RAM usage (dragging the scroll indicator for fast scrolling in 30 seconds)
iPhone 12, iOS 18.6.2
Test's scheme: link
| Approach | Result |
|---|---|
| LazyVStack | 24.5 MB. |
| List | 26 MB. |
| OptimizedVStack | 21.0 MB. |
🚀 Very fast! 🚀
- Only standard iOS SDK (Foundation, SwiftUI, UIKit, os)
Source code is released under the Apache License 2.0. See LICENSE for details.
