반응형
struct StickyTopSearchBar: View {
@State private var searchQuery = ""
@State private var offset: CGFloat = 0
@State private var startOffset: CGFloat = 0
@State private var titleOffset: CGFloat = 0
@State private var titleBarHeight: CGFloat = 0
var body: some View {
ZStack(alignment: .top) {
VStack {
if searchQuery == "" {
HStack {
Button {
} label: {
Image(systemName: "person")
.font(.title2)
.foregroundColor(.primary)
}
Spacer()
Button {
} label: {
Image(systemName: "plus")
.font(.title2)
.foregroundColor(.primary)
}
}
.padding()
HStack {
Text("Home")
.fontWeight(.bold)
.foregroundColor(.primary)
.font(.largeTitle)
.overlay(
GeometryReader { reader -> Color in
let width = reader.frame(in: .global).maxX
DispatchQueue.main.async {
if titleOffset == 0 {
titleOffset = width
}
}
return Color.clear
}
.frame(width: 0, height: 0)
)
.padding()
.scaleEffect(getScale())
.offset(getOffset())
Spacer()
}
}
VStack {
HStack(spacing: 15) {
Image(systemName: "magnifyingglass")
.font(.system(size: 23, weight: .bold))
.foregroundColor(.gray)
TextField("Search", text: $searchQuery)
}
.padding(.vertical, 10)
.padding(.horizontal)
.background(Color.primary.opacity(0.05))
.cornerRadius(8)
.padding(.horizontal)
if searchQuery == "" {
HStack {
Rectangle()
.fill(Color.gray.opacity(0.06))
.frame(height: 0.5)
}
.padding()
}
}
.offset(y: offset > 0 && searchQuery == "" ? (offset <= 95 ? -offset : -95) : 0)
}
.zIndex(1)
.padding(.bottom, getOffset().height)
.background(Color.white.ignoresSafeArea())
.overlay(
GeometryReader { reader -> Color in
let height = reader.frame(in: .global).maxY
DispatchQueue.main.async {
if titleBarHeight == 0 {
titleBarHeight = height - (UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0)
}
}
return Color.clear
}
)
.animation(.easeInOut, value: searchQuery != "")
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 10) {
ForEach(1..<15, id: \.self) { num in
ZStack {
Rectangle()
.foregroundColor(.blue)
.frame(height: 150)
.frame(maxWidth: .infinity)
.padding(10)
Text("\(num)")
}
}
}
.padding(.top, 10)
.padding(.top, searchQuery == "" ? titleBarHeight : 90)
.overlay(
GeometryReader { proxy -> Color in
let minY = proxy.frame(in: .global).minY
DispatchQueue.main.async {
/// to get original offset
/// ie from 0
/// just minus start offset
if startOffset == 0 {
startOffset = minY
}
offset = startOffset - minY
}
return Color.clear
}
, alignment: .top
)
}
}
}
func getOffset() -> CGSize {
var size: CGSize = .zero
let screenWidth = UIScreen.main.bounds.width / 2
let offsetForCalculation = min(max(offset, 0), 75)
size.width = min(offsetForCalculation * 2, screenWidth - titleOffset)
size.height = -offsetForCalculation
return size
}
func getScale() -> CGFloat {
if offset > 0 {
let screenWidth = UIScreen.main.bounds.width
let progress = 1 - (getOffset().width / screenWidth)
return max(progress, 0.9)
} else {
return 1
}
}
}
반응형
'Dev-iOS > UI' 카테고리의 다른 글
[UI] Custom Drawer (Side Menu)- (SwiftUI 2.0 - iOS 14 이상) (0) | 2023.07.21 |
---|---|
[UI] pull to refresh - (SwiftUI 2.0 - iOS 14 이하) (0) | 2023.07.12 |
[UI] Drag & Drop - (SwiftUI 2.0 - iOS 14 이상) (0) | 2023.07.12 |
[UI] 상단 탭 화면 with Animation (SwiftUI 2.0 - iOS 14 이상) (0) | 2023.07.11 |
[UI] Carousel (SwiftUI 2.0 - iOS 14 이상) (0) | 2023.07.11 |