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

View File

@@ -5,6 +5,10 @@ struct CreatorChannelView: View {
@StateObject private var viewModel = CreatorChannelViewModel() @StateObject private var viewModel = CreatorChannelViewModel()
@Environment(\.dismiss) private var dismiss @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()) { init(creatorId: Int, viewModel: CreatorChannelViewModel = CreatorChannelViewModel()) {
self.creatorId = creatorId self.creatorId = creatorId
@@ -12,25 +16,57 @@ struct CreatorChannelView: View {
} }
var body: some View { var body: some View {
ZStack { GeometryReader { proxy in
Color.black.ignoresSafeArea() let titleBarBottomY = proxy.safeAreaInsets.top + titleBarHeight
let backgroundProgress = clamp(1 - ((tabBarMinY - titleBarBottomY) / titleBarHeight))
let isTabBarSticky = tabBarMinY <= titleBarBottomY
ZStack(alignment: .top) { ZStack(alignment: .top) {
Color.black.ignoresSafeArea()
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 0) { VStack(spacing: 0) {
headerSection headerSection
tabBar 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 selectedTabContent
} }
} }
.ignoresSafeArea(.container, edges: .vertical)
titleBar if isTabBarSticky {
tabBar
.frame(height: tabBarHeight)
.offset(y: titleBarHeight)
} }
VStack(spacing: 0) {
Color.black
.opacity(backgroundProgress)
.frame(height: proxy.safeAreaInsets.top)
titleBar(backgroundProgress: backgroundProgress)
}
.ignoresSafeArea(.container, edges: .top)
if viewModel.isLoading { if viewModel.isLoading {
LoadingView() LoadingView()
} }
} }
}
.navigationBarBackButtonHidden(true) .navigationBarBackButtonHidden(true)
.onAppear { .onAppear {
if viewModel.hasLoaded == false { if viewModel.hasLoaded == false {
@@ -40,11 +76,11 @@ struct CreatorChannelView: View {
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1) .sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1)
} }
private var titleBar: some View { private func titleBar(backgroundProgress: CGFloat) -> some View {
CreatorChannelTitleBar( CreatorChannelTitleBar(
isFollow: viewModel.response?.creator.isFollow ?? false, isFollow: viewModel.response?.creator.isFollow ?? false,
isNotify: viewModel.response?.creator.isNotify ?? false, isNotify: viewModel.response?.creator.isNotify ?? false,
backgroundProgress: 0, backgroundProgress: backgroundProgress,
onTapBack: { onTapBack: {
dismiss() dismiss()
}, },
@@ -75,6 +111,17 @@ struct CreatorChannelView: View {
CreatorChannelTabBar(selectedTab: $viewModel.selectedTab) 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 @ViewBuilder
private var selectedTabContent: some View { private var selectedTabContent: some View {
CreatorChannelPlaceholderTabView(title: viewModel.selectedTab.title) CreatorChannelPlaceholderTabView(title: viewModel.selectedTab.title)