Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions daisy/StarbucksDaisy/StarbucksDaisy/Shop/View/OffsetModifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// OffsetModifier.swift
// StarbucksDaisy
//
// Created by 원주연 on 6/22/25.
//

import Foundation
import SwiftUI

struct OffsetModifier: ViewModifier {
@Binding var offset: CGFloat

var returnromStart: Bool = true
@State var startValue: CGFloat = 0

func body(content: Content) -> some View {
content
.overlay(content: {
GeometryReader(content: { proxy in
Color.clear
.preference(key: OffsetKey.self, value: proxy.frame(in: .named("SCROLL")).minY)
.onPreferenceChange(OffsetKey.self) { value in
if startValue == 0 {
startValue = value
}

offset = (value - (returnromStart ? startValue : 0))
}
})
})
}
}

struct OffsetKey: PreferenceKey {
static var defaultValue: CGFloat = 0

static func reduce(value: inout Value, nextValue: () -> Value) {
value = nextValue()
}
}
75 changes: 63 additions & 12 deletions daisy/StarbucksDaisy/StarbucksDaisy/Shop/View/ShopView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,36 @@ import SwiftUI
struct ShopView: View {
/// Best Items μ„Ήμ…˜μ˜ ν˜„μž¬ νŽ˜μ΄μ§€ μƒνƒœλ₯Ό 좔적
@State private var currentBestItemPage = 0
@State var headerOffsets: (CGFloat, CGFloat) = (0, 0)

var viewModel: ShopViewModel = .init()
let columns = Array(repeating: GridItem(.flexible()), count: 2)

var body: some View {
ScrollView {
VStack(spacing: 20) {
TopBanners
AllProducts
BestItems
NewProducts
}
headerView()
LazyVStack(spacing: 20, pinnedViews: [.sectionHeaders], content: {
Section(content: {
TopBanners
AllProducts
BestItems
NewProducts
}, header: {
pinnedHeaderView()
.modifier(OffsetModifier(offset: $headerOffsets.0, returnromStart: false))
.modifier(OffsetModifier(offset: $headerOffsets.1))
})
})
}
.padding(.horizontal, 16)
.safeAreaPadding(.bottom, 90)
.ignoresSafeArea()
.background(.white01)
.scrollIndicators(.hidden)
.coordinateSpace(name: "SCROLL")
}

private var TopBanners: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Starbucks Online Store")
.font(.mainTextBold24)

ScrollView(.horizontal) {
LazyHStack(spacing: 28) {
Image("shopBanner1")
Expand All @@ -42,8 +49,6 @@ struct ShopView: View {
}
}
.scrollIndicators(.hidden)
}
.padding(.top, 27)
}

private var AllProducts: some View {
Expand Down Expand Up @@ -146,6 +151,52 @@ struct ShopView: View {
.frame(maxHeight: 446)
}
}

@ViewBuilder
private func headerView() -> some View {
GeometryReader { proxy in
let minY = proxy.frame(in: .named("SCROLL")).minY
let size = proxy.size
let height = max(0, size.height + minY)

Rectangle()
.fill(Color.white01)
.frame(width: size.width, height: height, alignment: .top)
.offset(y: -minY)
}
.frame(height: 27)
}

@ViewBuilder
private func pinnedHeaderView() -> some View {

let threshhold = -(getScreenSize().height * 0.05)

HStack {
if headerOffsets.0 < threshhold {
Spacer()
}

Text("Starbucks Online Store")
.font(headerOffsets.0 < threshhold ? .mainTextBold16 : .mainTextBold24)
.animation(.easeInOut(duration: 0.2), value: headerOffsets.0)

Spacer()

}
.frame(height: 90, alignment: .bottomLeading)
.safeAreaPadding(.bottom, headerOffsets.0 < threshhold ? 16 : 0)
.background(Color.white01)
}
}

extension View {
func getScreenSize() -> CGSize {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
return .zero
}
return windowScene.screen.bounds.size
}
}

#Preview {
Expand Down