Created
March 8, 2025 18:17
-
-
Save samsonjs/d2973f1c61014671601b442ca7eb8d97 to your computer and use it in GitHub Desktop.
Dynamic SwiftUI view that pins a header above a scroll view's contents, except at larger dynamic type sizes where it makes the header part of the scrolling content.
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
import SwiftUI | |
/// Dynamic SwiftUI view that pins a header above a scroll view's contents, except at larger dynamic type sizes where it makes the header part of the scrolling content. | |
struct DynamicTypePinnedHeaderView<Header: View, Footer: View, Content: View>: View { | |
let inlineThreshold: DynamicTypeSize | |
let header: Header | |
let footer: Footer | |
let content: Content | |
@Environment(\.dynamicTypeSize) private var typeSize | |
init( | |
inlineThreshold: DynamicTypeSize = .accessibility1, | |
@ViewBuilder header: () -> Header, | |
@ViewBuilder footer: () -> Footer, | |
@ViewBuilder content: () -> Content | |
) { | |
self.inlineThreshold = inlineThreshold | |
self.header = header() | |
self.footer = footer() | |
self.content = content() | |
} | |
var body: some View { | |
if typeSize >= inlineThreshold { | |
VStack(spacing: 0) { | |
ScrollView { | |
VStack(spacing: 0) { | |
header | |
content | |
} | |
} | |
footer | |
} | |
} else { | |
VStack(spacing: 0) { | |
header | |
ScrollView { | |
content | |
} | |
footer | |
} | |
} | |
} | |
} | |
#Preview { | |
DynamicTypePinnedHeaderView(header: { | |
DynamicTypeAdaptiveStack(verticalThreshold: .accessibility1) { | |
Group { | |
Text("cool stuff up here") | |
Text("lots") | |
Text("of") | |
Text("it,") | |
Text("too!") | |
} | |
.padding(.vertical) | |
} | |
.bold() | |
.padding() | |
.frame(maxWidth: .infinity) | |
.background(Color.accentColor) | |
}, footer: { | |
Button {} label: { | |
Label("reticulate splines", systemImage: "tortoise") | |
.padding(.vertical, 8) | |
.frame(maxWidth: .infinity) | |
} | |
.buttonStyle(.borderedProminent) | |
.padding() | |
}, content: { | |
VStack { | |
ForEach(0..<200) { _ in | |
Text("all work and no play makes jack a dull boy") | |
} | |
} | |
.frame(maxWidth: .infinity) | |
.background(Color(.secondarySystemBackground)) | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment