As promised, here is the SwiftUI view code that uses this modifier:
code-block
import SwiftUI
struct GridListView: View {
@State private var paddingToTop: CGFloat = 68.0
private let expandedPaddingToTop: CGFloat = 68.0
private let paddingBetweenL2AndL3: CGFloat = 24.0
private let L3Height: CGFloat = 44.0
@State private var items: [Int] = Array(1...100)
@State private var isLoading: Bool = false
private var L3Opacity: CGFloat {
pow(paddingToTop / expandedPaddingToTop, 5)
}
private var L3YOffset: CGFloat {
-L3Height + (paddingToTop - paddingBetweenL2AndL3)
}
var body: some View {
ZStack {
List {
// Show loaded items
ForEach(Array(stride(from: 0, to: items.count, by: 2)), id: \.self) { index in
HStack {
GridItemView(item: items[index])
if index + 1 < items.count {
GridItemView(item: items[index + 1])
} else {
Spacer()
}
}
.listRowInsets(EdgeInsets())
.padding(.vertical, 8)
.onAppear {
// Detect when user reaches near the end
if index == items.count - 2 {
loadMoreItemsIfNeeded()
}
}
}
// Show placeholders while loading
if isLoading {
ForEach(0..<500) { _ in
HStack {
GridItemPlaceholder()
GridItemPlaceholder()
}
.listRowInsets(EdgeInsets())
.padding(.vertical, 8)
}
}
}
.padding(.top, max(paddingToTop, 8.0))
.listStyle(.plain)
.modifier(
L3CollapseHeaderIOS18(
currentHeight: $paddingToTop,
expectedHeight: expandedPaddingToTop,
isViewVisible: true
)
)
}
.overlay(alignment: .top) {
VStack {
Text("Overlay Title")
.font(.headline)
.foregroundColor(.white)
}
.frame(maxWidth: .infinity, minHeight: 68.0)
.background(Color.red)
.opacity(L3Opacity)
.offset(y: L3YOffset)
}
}
private func loadMoreItemsIfNeeded() {
guard !isLoading else { return }
isLoading = true
Task {
// Simulate 2-second network delay
try? await Task.sleep(nanoseconds: 2_000_000_000)
// Add 1000 new items
let nextItems = (items.count + 1)...(items.count + 1000)
items.append(contentsOf: nextItems)
isLoading = false
}
}
}
struct GridItemView: View {
let item: Int
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 12)
.fill(Color.blue.opacity(0.2))
.frame(height: 50)
Text("Item \(item)")
.font(.headline)
}
.padding(.horizontal, 8)
}
}
struct GridItemPlaceholder: View {
var body: some View {
RoundedRectangle(cornerRadius: 12)
.fill(Color.gray.opacity(0.2))
.frame(height: 50)
.redacted(reason: .placeholder)
.padding(.horizontal, 8)
}
}
#Preview {
GridListView()
}