// // OffsetObservableScollView.swift // AcaMate // // Created by TAnine on 2/10/25. // import SwiftUI import Combine struct OffsetObservableScrollView: View { var axes: Axis.Set = .vertical var showsIndicators: Bool = true @Binding var scrollOffset: CGPoint @ViewBuilder var content: (ScrollViewProxy) -> Content @Namespace var coordinateSpaceName: Namespace.ID init( _ axes: Axis.Set = .vertical, showsIndicators: Bool = true, scrollOffset: Binding, @ViewBuilder content: @escaping (ScrollViewProxy) -> Content ) { self.axes = axes self.showsIndicators = showsIndicators self._scrollOffset = scrollOffset self.content = content } var body: some View { ScrollView(axes, showsIndicators: showsIndicators) { ScrollViewReader { scrollViewProxy in VStack(spacing: 0) { // 맨 위로 스크롤하기 위한 anchor 뷰 (id "TOP") Color.clear .frame(height: 1) .id("TOP") content(scrollViewProxy) .overlay { GeometryReader { geometryProxy in Color.clear .preference( key: ScrollOffsetPreferenceKey.self, value: CGPoint ( x: -geometryProxy.frame(in: .named(coordinateSpaceName)).minX, y: -geometryProxy.frame(in: .named(coordinateSpaceName)).minY ) ) } } } } } .coordinateSpace(name: coordinateSpaceName) .onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in // printLog("\(scrollOffset) -> \(value)") scrollOffset = value } } } struct ScrollOffsetPreferenceKey: PreferenceKey { static var defaultValue: CGPoint = .zero static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) { value = nextValue() } }