Created
September 17, 2025 20:56
-
-
Save modemlooper/597c441b630ac05d69c95e2b00f6a1a2 to your computer and use it in GitHub Desktop.
swiftui stretchy header
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 | |
| /// A reusable SwiftUI view that features a stretchy header positioned below a navigation bar. | |
| /// | |
| /// This view is generic and accepts two custom view builders ("slots"): | |
| /// - `header`: The content to display in the stretchy header area. | |
| /// - `content`: The main scrollable content to display below the header. | |
| struct ReusableStretchyHeaderView<HeaderContent: View, MainContent: View>: View { | |
| // MARK: Properties | |
| private let headerHeight: CGFloat | |
| private let header: () -> HeaderContent | |
| private let content: () -> MainContent | |
| // MARK: Initializer | |
| init( | |
| headerHeight: CGFloat = 220, | |
| @ViewBuilder header: @escaping () -> HeaderContent, | |
| @ViewBuilder content: @escaping () -> MainContent | |
| ) { | |
| self.headerHeight = headerHeight | |
| self.header = header | |
| self.content = content | |
| } | |
| // MARK: Body | |
| var body: some View { | |
| ScrollView(.vertical, showsIndicators: false) { | |
| VStack(spacing: 0) { | |
| // Header slot | |
| GeometryReader { geometry in | |
| let minY = geometry.frame(in: .named("scroll")).minY | |
| let isStretching = minY > 0 | |
| let height = isStretching ? headerHeight + minY : headerHeight | |
| let yOffset = isStretching ? -minY : 0 | |
| // The ZStack ensures the user's header content is properly framed and clipped. | |
| ZStack { | |
| header() | |
| } | |
| .frame(width: geometry.size.width, height: height) | |
| .clipped() | |
| .offset(y: yOffset) | |
| } | |
| .frame(height: headerHeight) | |
| // Main content slot | |
| content() | |
| } | |
| } | |
| .coordinateSpace(name: "scroll") | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment