Skip to content

Instantly share code, notes, and snippets.

@uhooi
Last active December 22, 2023 12:32
Show Gist options
  • Save uhooi/02055818549c429621afa3ebbd678acb to your computer and use it in GitHub Desktop.
Save uhooi/02055818549c429621afa3ebbd678acb to your computer and use it in GitHub Desktop.
上部と下部で背景色が異なるスクロールビューの完全な実装
import SwiftUI
/// 上部と下部で背景色が異なるスクロールビュー
///
/// - seeAlso: https://x.com/ynoseda/status/1737120393960558947
public struct DualBackgroundColorScrollView<Content: View>: View {
private let topBackgroundColor: Color
private let bottomBackgroundColor: Color
private let content: () -> Content
@State private var scrollContentViewMinY: CGFloat = 0
@State private var scrollViewHeight: CGFloat = 0
public var body: some View {
ScrollView {
content()
.overlay {
GeometryReader { proxy in
Color.clear
.preference(
key: ScrollContentViewMinYPreferenceKey.self,
value: [proxy.frame(in: .global).minY]
)
}
}
}
.background {
VStack(spacing: 0) {
topBackgroundColor
.frame(height: max(scrollContentViewMinY, 0))
bottomBackgroundColor
.frame(height: scrollViewHeight - scrollContentViewMinY)
}
.ignoresSafeArea()
}
.overlay {
GeometryReader { proxy in
Color.clear
.onAppear {
scrollViewHeight = proxy.frame(in: .global).height
}
}
.ignoresSafeArea()
}
.onPreferenceChange(ScrollContentViewMinYPreferenceKey.self) { value in
scrollContentViewMinY = value[0]
}
}
public init(
topBackgroundColor: Color,
bottomBackgroundColor: Color,
content: @escaping () -> Content
) {
self.topBackgroundColor = topBackgroundColor
self.bottomBackgroundColor = bottomBackgroundColor
self.content = content
}
}
// MARK: - Privates
private struct ScrollContentViewMinYPreferenceKey: PreferenceKey {
static var defaultValue: [CGFloat] = [0]
static func reduce(value: inout [CGFloat], nextValue: () -> [CGFloat]) {
value.append(contentsOf: nextValue())
}
}
// MARK: - Previews
#Preview {
DualBackgroundColorScrollView(
topBackgroundColor: .red,
bottomBackgroundColor: .blue
) {
VStack(spacing: 0) {
Color.red
.frame(height: 400)
Color.green
.frame(height: 400)
Color.blue
.frame(height: 400)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment