forked from JJUNGTABLE/iOS
104 lines
3.5 KiB
Swift
104 lines
3.5 KiB
Swift
//
|
|
// ScorllView_Example.swift
|
|
// RememberbyAnything
|
|
//
|
|
// Created by Sean Kim on 5/14/24.
|
|
//
|
|
import SwiftUI
|
|
|
|
struct ScorllView_Example: View {
|
|
@StateObject private var scrollViewModel: ScrollViewModel = ScrollViewModel()
|
|
@State var isStartScroll: Bool = true
|
|
|
|
// scroll 위치 감지 변경하는 부분
|
|
private var scrollObservableView: some View {
|
|
GeometryReader { proxy in
|
|
let offsetY = proxy.frame(in: .global).origin.y
|
|
Color.clear
|
|
.preference(
|
|
key: ScrollOffsetKey.self,
|
|
value: offsetY
|
|
|
|
)
|
|
.onAppear {
|
|
scrollViewModel.setOriginOffset(offsetY)
|
|
}
|
|
}
|
|
.frame(height: 0)
|
|
}
|
|
|
|
var body: some View {
|
|
ScrollViewReader { scroll in
|
|
ScrollView(showsIndicators: false) {
|
|
scrollObservableView.id(-1)
|
|
}
|
|
.onPreferenceChange(ScrollOffsetKey.self) {
|
|
scrollViewModel.setOffset($0)
|
|
self.isStartScroll = scrollViewModel.isStartScroll
|
|
}
|
|
// 스크롤이 시작할 경우 최상단으로 올리는 버튼 그리기
|
|
.overlay(alignment: .top) {
|
|
if isStartScroll {
|
|
GeometryReader { geo in
|
|
Button {
|
|
withAnimation {
|
|
scroll.scrollTo(-1, anchor: .center)
|
|
}
|
|
} label: {
|
|
Icon.up
|
|
.font(.nps(size: 30))
|
|
.foregroundStyle(.brandDeepBlue)
|
|
.frame(width: geo.size.width, height: isStartScroll ? 30 : 0,alignment: .center)
|
|
.padding(.init(top: 10, leading: 0, bottom: 20, trailing: 0))
|
|
.background(
|
|
LinearGradient(
|
|
colors: [.whiteSora, .whiteSora.opacity(0)],
|
|
startPoint: .top,
|
|
endPoint: .bottom)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
// MARK: - 스크롤 뷰 관련 modifier
|
|
struct HeightPreferenceKey: PreferenceKey {
|
|
static var defaultValue: CGFloat = 0
|
|
|
|
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
|
value = nextValue()
|
|
}
|
|
}
|
|
|
|
// 자식뷰에서 상위 뷰로 데이터 전달시 사용 = PreferenceKey
|
|
struct ScrollOffsetKey: PreferenceKey {
|
|
static var defaultValue: CGFloat = .zero
|
|
|
|
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
|
value += nextValue()
|
|
}
|
|
}
|
|
|
|
final class ScrollViewModel: ObservableObject {
|
|
@Published var offset: CGFloat = 0
|
|
@Published var isStartScroll: Bool = false
|
|
var originOffset: CGFloat = 0
|
|
var isCheckedOriginOffset: Bool = false
|
|
|
|
func setOriginOffset(_ offset: CGFloat) {
|
|
guard !isCheckedOriginOffset else { return }
|
|
self.originOffset = offset - 30 // 스크롤 패딩 넣은거 만큼 빼야 함
|
|
self.offset = offset
|
|
isCheckedOriginOffset = true
|
|
}
|
|
|
|
func setOffset(_ offset: CGFloat) {
|
|
self.offset = offset
|
|
if self.offset < self.originOffset { isStartScroll = true }
|
|
else { isStartScroll = false }
|
|
}
|
|
}
|