feat(creator): 채널 탭 고정을 연결한다

This commit is contained in:
Yu Sung
2026-07-03 01:34:40 +09:00
parent 6cebf3052c
commit f19b04dc0e
2 changed files with 62 additions and 11 deletions

View File

@@ -12,7 +12,7 @@ struct CreatorChannelTitleBar: View {
let onTapMore: () -> Void
var body: some View {
HStack(spacing: 0) {
HStack(spacing: SodaSpacing.s12) {
Button(action: onTapBack) {
Image("ic_new_bar_back")
.resizable()
@@ -20,6 +20,10 @@ struct CreatorChannelTitleBar: View {
}
.buttonStyle(.plain)
Text("")
.appFont(.heading2)
Spacer(minLength: 0)
HStack(spacing: SodaSpacing.s14) {

View File

@@ -5,6 +5,10 @@ struct CreatorChannelView: View {
@StateObject private var viewModel = CreatorChannelViewModel()
@Environment(\.dismiss) private var dismiss
@State private var tabBarMinY: CGFloat = .greatestFiniteMagnitude
private let titleBarHeight: CGFloat = 56
private let tabBarHeight: CGFloat = 52
init(creatorId: Int, viewModel: CreatorChannelViewModel = CreatorChannelViewModel()) {
self.creatorId = creatorId
@@ -12,23 +16,55 @@ struct CreatorChannelView: View {
}
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
GeometryReader { proxy in
let titleBarBottomY = proxy.safeAreaInsets.top + titleBarHeight
let backgroundProgress = clamp(1 - ((tabBarMinY - titleBarBottomY) / titleBarHeight))
let isTabBarSticky = tabBarMinY <= titleBarBottomY
ZStack(alignment: .top) {
Color.black.ignoresSafeArea()
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 0) {
headerSection
tabBar
.background(
GeometryReader { geometry in
let minY = geometry.frame(in: .global).minY
Color.clear
.onAppear {
updateTabBarMinY(minY)
}
.onChange(of: minY) { value in
updateTabBarMinY(value)
}
}
)
.opacity(isTabBarSticky ? 0 : 1)
selectedTabContent
}
}
.ignoresSafeArea(.container, edges: .vertical)
if isTabBarSticky {
tabBar
.frame(height: tabBarHeight)
.offset(y: titleBarHeight)
}
titleBar
}
if viewModel.isLoading {
LoadingView()
VStack(spacing: 0) {
Color.black
.opacity(backgroundProgress)
.frame(height: proxy.safeAreaInsets.top)
titleBar(backgroundProgress: backgroundProgress)
}
.ignoresSafeArea(.container, edges: .top)
if viewModel.isLoading {
LoadingView()
}
}
}
.navigationBarBackButtonHidden(true)
@@ -40,11 +76,11 @@ struct CreatorChannelView: View {
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1)
}
private var titleBar: some View {
private func titleBar(backgroundProgress: CGFloat) -> some View {
CreatorChannelTitleBar(
isFollow: viewModel.response?.creator.isFollow ?? false,
isNotify: viewModel.response?.creator.isNotify ?? false,
backgroundProgress: 0,
backgroundProgress: backgroundProgress,
onTapBack: {
dismiss()
},
@@ -75,6 +111,17 @@ struct CreatorChannelView: View {
CreatorChannelTabBar(selectedTab: $viewModel.selectedTab)
}
private func clamp(_ value: CGFloat) -> CGFloat {
max(0, min(value, 1))
}
private func updateTabBarMinY(_ value: CGFloat) {
guard tabBarMinY != value else { return }
DispatchQueue.main.async {
tabBarMinY = value
}
}
@ViewBuilder
private var selectedTabContent: some View {
CreatorChannelPlaceholderTabView(title: viewModel.selectedTab.title)