From 2052492912063800f866ca8c2b73243704b0f0bf Mon Sep 17 00:00:00 2001 From: cheykrym Date: Fri, 25 Jul 2025 01:58:34 +0300 Subject: [PATCH] top bar test --- Shared/Components/RefreshableScrollView.swift | 12 +++-- Shared/Views/Tab/HomeTab.swift | 10 ++-- Shared/Views/Tab/MainView.swift | 47 ++++++++++++++----- Shared/Views/Tab/ProfileTab.swift | 10 ++-- 4 files changed, 58 insertions(+), 21 deletions(-) diff --git a/Shared/Components/RefreshableScrollView.swift b/Shared/Components/RefreshableScrollView.swift index 561ee30..bd6611a 100644 --- a/Shared/Components/RefreshableScrollView.swift +++ b/Shared/Components/RefreshableScrollView.swift @@ -4,17 +4,20 @@ import UIKit struct RefreshableScrollView: UIViewRepresentable { var content: Content var onRefresh: () -> Void + var onScroll: ((CGPoint) -> Void)? var isRefreshing: Binding - init(isRefreshing: Binding, onRefresh: @escaping () -> Void, @ViewBuilder content: () -> Content) { + init(isRefreshing: Binding, onRefresh: @escaping () -> Void, onScroll: ((CGPoint) -> Void)? = nil, @ViewBuilder content: () -> Content) { self.content = content() self.onRefresh = onRefresh + self.onScroll = onScroll self.isRefreshing = isRefreshing } func makeUIView(context: Context) -> UIScrollView { let scrollView = UIScrollView() scrollView.delaysContentTouches = false + scrollView.delegate = context.coordinator let refreshControl = UIRefreshControl() refreshControl.addTarget(context.coordinator, action: #selector(Coordinator.handleRefresh), for: .valueChanged) @@ -41,7 +44,6 @@ struct RefreshableScrollView: UIViewRepresentable { if isRefreshing.wrappedValue { uiView.refreshControl?.beginRefreshing() } else { - // Отложенное завершение, чтобы избежать цикла обновлений DispatchQueue.main.async { uiView.refreshControl?.endRefreshing() } @@ -54,7 +56,7 @@ struct RefreshableScrollView: UIViewRepresentable { Coordinator(self) } - class Coordinator: NSObject { + class Coordinator: NSObject, UIScrollViewDelegate { var parent: RefreshableScrollView var hostingController: UIHostingController? @@ -65,5 +67,9 @@ struct RefreshableScrollView: UIViewRepresentable { @objc func handleRefresh() { parent.onRefresh() } + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + parent.onScroll?(scrollView.contentOffset) + } } } diff --git a/Shared/Views/Tab/HomeTab.swift b/Shared/Views/Tab/HomeTab.swift index 5d3645d..6ab2619 100644 --- a/Shared/Views/Tab/HomeTab.swift +++ b/Shared/Views/Tab/HomeTab.swift @@ -4,15 +4,19 @@ struct HomeTab: View { @State private var posts: [Post] = [] @State private var isLoading = true @State private var isRefreshing = false + + var onScroll: ((CGPoint) -> Void)? var body: some View { VStack { if isLoading { ProgressView("Загрузка ленты...") } else { - RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: { - fetchData() - }) { + RefreshableScrollView( + isRefreshing: $isRefreshing, + onRefresh: { fetchData() }, + onScroll: onScroll + ) { LazyVStack(spacing: 24) { ForEach(posts) { post in PostDetailView(post: post) diff --git a/Shared/Views/Tab/MainView.swift b/Shared/Views/Tab/MainView.swift index 81da0d3..47630fd 100644 --- a/Shared/Views/Tab/MainView.swift +++ b/Shared/Views/Tab/MainView.swift @@ -11,10 +11,14 @@ struct MainView: View { @ObservedObject var viewModel: LoginViewModel @State private var selectedTab: Int = 0 - // Состояния для TopBarView, когда активна вкладка Profile + // Состояния для TopBarView @State private var selectedAccount = "@user1" @State private var accounts = ["@user1", "@user2", "@user3"] @State private var sheetType: ProfileTab.SheetType? = nil + + // Состояния для скрытия TopBar + @State private var topBarVisible = true + @State private var lastScrollY: CGFloat = 0 private var tabTitle: String { switch selectedTab { @@ -32,7 +36,7 @@ struct MainView: View { } var body: some View { - NavigationView { // NavigationView нужен здесь для NavigationLink в TopBarView + NavigationView { VStack(spacing: 0) { TopBarView( title: tabTitle, @@ -41,38 +45,38 @@ struct MainView: View { accounts: accounts, viewModel: viewModel ) + .offset(y: topBarVisible ? 0 : -100) + .animation(.spring(response: 0.4, dampingFraction: 0.8), value: topBarVisible) ZStack { switch selectedTab { case 0: - HomeTab() + HomeTab(onScroll: handleScroll) case 1: - SearchTab() + SearchTab() // SearchTab не имеет скролла, поэтому onScroll не нужен case 2: - ChatsTab() + ChatsTab() // ChatsTab тоже case 3: - // Передаем состояния в ProfileTab ProfileTab( viewModel: viewModel, sheetType: $sheetType, selectedAccount: $selectedAccount, - accounts: $accounts + accounts: $accounts, + onScroll: handleScroll ) default: - HomeTab() + HomeTab(onScroll: handleScroll) } } .frame(maxWidth: .infinity, maxHeight: .infinity) CustomTabBar(selectedTab: $selectedTab) { - // Действие для кнопки "Создать" print("Create button tapped") } } .ignoresSafeArea(edges: .bottom) - .navigationBarHidden(true) // Скрываем стандартный NavigationBar + .navigationBarHidden(true) .sheet(item: $sheetType) { type in - // Обработка sheet, перенесенная из ProfileTab switch type { case .accountShare: AccountShareSheet( @@ -86,7 +90,26 @@ struct MainView: View { } } } - .navigationViewStyle(StackNavigationViewStyle()) // Важно для корректной работы + .navigationViewStyle(StackNavigationViewStyle()) + } + + private func handleScroll(offset: CGPoint) { + let currentY = offset.y + + // Показываем бар, если скроллим вверх или дошли до верха + if currentY < lastScrollY || currentY <= 0 { + if !topBarVisible { + topBarVisible = true + } + } + // Скрываем, если скроллим вниз и отступили от верха + else if currentY > lastScrollY && currentY > 50 { + if topBarVisible { + topBarVisible = false + } + } + + lastScrollY = currentY } } diff --git a/Shared/Views/Tab/ProfileTab.swift b/Shared/Views/Tab/ProfileTab.swift index 3af6100..40afe5d 100644 --- a/Shared/Views/Tab/ProfileTab.swift +++ b/Shared/Views/Tab/ProfileTab.swift @@ -8,6 +8,8 @@ struct ProfileTab: View { @Binding var sheetType: SheetType? @Binding var selectedAccount: String @Binding var accounts: [String] + + var onScroll: ((CGPoint) -> Void)? let followers = ["@alice", "@bob", "@charlie"] let following = ["@dev", "@design", "@ios"] @@ -47,9 +49,11 @@ struct ProfileTab: View { ) } - RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: { - fetchData() - }) { + RefreshableScrollView( + isRefreshing: $isRefreshing, + onRefresh: { fetchData() }, + onScroll: onScroll + ) { VStack(spacing: 12) { header .frame(maxWidth: .infinity)