top bar test
This commit is contained in:
		
							parent
							
								
									975802dc88
								
							
						
					
					
						commit
						2052492912
					
				@ -4,17 +4,20 @@ import UIKit
 | 
				
			|||||||
struct RefreshableScrollView<Content: View>: UIViewRepresentable {
 | 
					struct RefreshableScrollView<Content: View>: UIViewRepresentable {
 | 
				
			||||||
    var content: Content
 | 
					    var content: Content
 | 
				
			||||||
    var onRefresh: () -> Void
 | 
					    var onRefresh: () -> Void
 | 
				
			||||||
 | 
					    var onScroll: ((CGPoint) -> Void)?
 | 
				
			||||||
    var isRefreshing: Binding<Bool>
 | 
					    var isRefreshing: Binding<Bool>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init(isRefreshing: Binding<Bool>, onRefresh: @escaping () -> Void, @ViewBuilder content: () -> Content) {
 | 
					    init(isRefreshing: Binding<Bool>, onRefresh: @escaping () -> Void, onScroll: ((CGPoint) -> Void)? = nil, @ViewBuilder content: () -> Content) {
 | 
				
			||||||
        self.content = content()
 | 
					        self.content = content()
 | 
				
			||||||
        self.onRefresh = onRefresh
 | 
					        self.onRefresh = onRefresh
 | 
				
			||||||
 | 
					        self.onScroll = onScroll
 | 
				
			||||||
        self.isRefreshing = isRefreshing
 | 
					        self.isRefreshing = isRefreshing
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func makeUIView(context: Context) -> UIScrollView {
 | 
					    func makeUIView(context: Context) -> UIScrollView {
 | 
				
			||||||
        let scrollView = UIScrollView()
 | 
					        let scrollView = UIScrollView()
 | 
				
			||||||
        scrollView.delaysContentTouches = false
 | 
					        scrollView.delaysContentTouches = false
 | 
				
			||||||
 | 
					        scrollView.delegate = context.coordinator
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        let refreshControl = UIRefreshControl()
 | 
					        let refreshControl = UIRefreshControl()
 | 
				
			||||||
        refreshControl.addTarget(context.coordinator, action: #selector(Coordinator.handleRefresh), for: .valueChanged)
 | 
					        refreshControl.addTarget(context.coordinator, action: #selector(Coordinator.handleRefresh), for: .valueChanged)
 | 
				
			||||||
@ -41,7 +44,6 @@ struct RefreshableScrollView<Content: View>: UIViewRepresentable {
 | 
				
			|||||||
        if isRefreshing.wrappedValue {
 | 
					        if isRefreshing.wrappedValue {
 | 
				
			||||||
            uiView.refreshControl?.beginRefreshing()
 | 
					            uiView.refreshControl?.beginRefreshing()
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // Отложенное завершение, чтобы избежать цикла обновлений
 | 
					 | 
				
			||||||
            DispatchQueue.main.async {
 | 
					            DispatchQueue.main.async {
 | 
				
			||||||
                uiView.refreshControl?.endRefreshing()
 | 
					                uiView.refreshControl?.endRefreshing()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -54,7 +56,7 @@ struct RefreshableScrollView<Content: View>: UIViewRepresentable {
 | 
				
			|||||||
        Coordinator(self)
 | 
					        Coordinator(self)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Coordinator: NSObject {
 | 
					    class Coordinator: NSObject, UIScrollViewDelegate {
 | 
				
			||||||
        var parent: RefreshableScrollView
 | 
					        var parent: RefreshableScrollView
 | 
				
			||||||
        var hostingController: UIHostingController<Content>?
 | 
					        var hostingController: UIHostingController<Content>?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -65,5 +67,9 @@ struct RefreshableScrollView<Content: View>: UIViewRepresentable {
 | 
				
			|||||||
        @objc func handleRefresh() {
 | 
					        @objc func handleRefresh() {
 | 
				
			||||||
            parent.onRefresh()
 | 
					            parent.onRefresh()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        func scrollViewDidScroll(_ scrollView: UIScrollView) {
 | 
				
			||||||
 | 
					            parent.onScroll?(scrollView.contentOffset)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,15 +4,19 @@ struct HomeTab: View {
 | 
				
			|||||||
    @State private var posts: [Post] = []
 | 
					    @State private var posts: [Post] = []
 | 
				
			||||||
    @State private var isLoading = true
 | 
					    @State private var isLoading = true
 | 
				
			||||||
    @State private var isRefreshing = false
 | 
					    @State private var isRefreshing = false
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    var onScroll: ((CGPoint) -> Void)?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var body: some View {
 | 
					    var body: some View {
 | 
				
			||||||
        VStack {
 | 
					        VStack {
 | 
				
			||||||
            if isLoading {
 | 
					            if isLoading {
 | 
				
			||||||
                ProgressView("Загрузка ленты...")
 | 
					                ProgressView("Загрузка ленты...")
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: {
 | 
					                RefreshableScrollView(
 | 
				
			||||||
                    fetchData()
 | 
					                    isRefreshing: $isRefreshing,
 | 
				
			||||||
                }) {
 | 
					                    onRefresh: { fetchData() },
 | 
				
			||||||
 | 
					                    onScroll: onScroll
 | 
				
			||||||
 | 
					                ) {
 | 
				
			||||||
                    LazyVStack(spacing: 24) {
 | 
					                    LazyVStack(spacing: 24) {
 | 
				
			||||||
                        ForEach(posts) { post in
 | 
					                        ForEach(posts) { post in
 | 
				
			||||||
                            PostDetailView(post: post)
 | 
					                            PostDetailView(post: post)
 | 
				
			||||||
 | 
				
			|||||||
@ -11,10 +11,14 @@ struct MainView: View {
 | 
				
			|||||||
    @ObservedObject var viewModel: LoginViewModel
 | 
					    @ObservedObject var viewModel: LoginViewModel
 | 
				
			||||||
    @State private var selectedTab: Int = 0
 | 
					    @State private var selectedTab: Int = 0
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Состояния для TopBarView, когда активна вкладка Profile
 | 
					    // Состояния для TopBarView
 | 
				
			||||||
    @State private var selectedAccount = "@user1"
 | 
					    @State private var selectedAccount = "@user1"
 | 
				
			||||||
    @State private var accounts = ["@user1", "@user2", "@user3"]
 | 
					    @State private var accounts = ["@user1", "@user2", "@user3"]
 | 
				
			||||||
    @State private var sheetType: ProfileTab.SheetType? = nil
 | 
					    @State private var sheetType: ProfileTab.SheetType? = nil
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Состояния для скрытия TopBar
 | 
				
			||||||
 | 
					    @State private var topBarVisible = true
 | 
				
			||||||
 | 
					    @State private var lastScrollY: CGFloat = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private var tabTitle: String {
 | 
					    private var tabTitle: String {
 | 
				
			||||||
        switch selectedTab {
 | 
					        switch selectedTab {
 | 
				
			||||||
@ -32,7 +36,7 @@ struct MainView: View {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var body: some View {
 | 
					    var body: some View {
 | 
				
			||||||
        NavigationView { // NavigationView нужен здесь для NavigationLink в TopBarView
 | 
					        NavigationView {
 | 
				
			||||||
            VStack(spacing: 0) {
 | 
					            VStack(spacing: 0) {
 | 
				
			||||||
                TopBarView(
 | 
					                TopBarView(
 | 
				
			||||||
                    title: tabTitle,
 | 
					                    title: tabTitle,
 | 
				
			||||||
@ -41,38 +45,38 @@ struct MainView: View {
 | 
				
			|||||||
                    accounts: accounts,
 | 
					                    accounts: accounts,
 | 
				
			||||||
                    viewModel: viewModel
 | 
					                    viewModel: viewModel
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					                .offset(y: topBarVisible ? 0 : -100)
 | 
				
			||||||
 | 
					                .animation(.spring(response: 0.4, dampingFraction: 0.8), value: topBarVisible)
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                ZStack {
 | 
					                ZStack {
 | 
				
			||||||
                    switch selectedTab {
 | 
					                    switch selectedTab {
 | 
				
			||||||
                    case 0:
 | 
					                    case 0:
 | 
				
			||||||
                        HomeTab()
 | 
					                        HomeTab(onScroll: handleScroll)
 | 
				
			||||||
                    case 1:
 | 
					                    case 1:
 | 
				
			||||||
                        SearchTab()
 | 
					                        SearchTab() // SearchTab не имеет скролла, поэтому onScroll не нужен
 | 
				
			||||||
                    case 2:
 | 
					                    case 2:
 | 
				
			||||||
                        ChatsTab()
 | 
					                        ChatsTab() // ChatsTab тоже
 | 
				
			||||||
                    case 3:
 | 
					                    case 3:
 | 
				
			||||||
                        // Передаем состояния в ProfileTab
 | 
					 | 
				
			||||||
                        ProfileTab(
 | 
					                        ProfileTab(
 | 
				
			||||||
                            viewModel: viewModel,
 | 
					                            viewModel: viewModel,
 | 
				
			||||||
                            sheetType: $sheetType,
 | 
					                            sheetType: $sheetType,
 | 
				
			||||||
                            selectedAccount: $selectedAccount,
 | 
					                            selectedAccount: $selectedAccount,
 | 
				
			||||||
                            accounts: $accounts
 | 
					                            accounts: $accounts,
 | 
				
			||||||
 | 
					                            onScroll: handleScroll
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                    default:
 | 
					                    default:
 | 
				
			||||||
                        HomeTab()
 | 
					                        HomeTab(onScroll: handleScroll)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                .frame(maxWidth: .infinity, maxHeight: .infinity)
 | 
					                .frame(maxWidth: .infinity, maxHeight: .infinity)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                CustomTabBar(selectedTab: $selectedTab) {
 | 
					                CustomTabBar(selectedTab: $selectedTab) {
 | 
				
			||||||
                    // Действие для кнопки "Создать"
 | 
					 | 
				
			||||||
                    print("Create button tapped")
 | 
					                    print("Create button tapped")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            .ignoresSafeArea(edges: .bottom)
 | 
					            .ignoresSafeArea(edges: .bottom)
 | 
				
			||||||
            .navigationBarHidden(true) // Скрываем стандартный NavigationBar
 | 
					            .navigationBarHidden(true)
 | 
				
			||||||
            .sheet(item: $sheetType) { type in
 | 
					            .sheet(item: $sheetType) { type in
 | 
				
			||||||
                // Обработка sheet, перенесенная из ProfileTab
 | 
					 | 
				
			||||||
                switch type {
 | 
					                switch type {
 | 
				
			||||||
                case .accountShare:
 | 
					                case .accountShare:
 | 
				
			||||||
                    AccountShareSheet(
 | 
					                    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
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,8 @@ struct ProfileTab: View {
 | 
				
			|||||||
    @Binding var sheetType: SheetType?
 | 
					    @Binding var sheetType: SheetType?
 | 
				
			||||||
    @Binding var selectedAccount: String
 | 
					    @Binding var selectedAccount: String
 | 
				
			||||||
    @Binding var accounts: [String]
 | 
					    @Binding var accounts: [String]
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    var onScroll: ((CGPoint) -> Void)?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let followers = ["@alice", "@bob", "@charlie"]
 | 
					    let followers = ["@alice", "@bob", "@charlie"]
 | 
				
			||||||
    let following = ["@dev", "@design", "@ios"]
 | 
					    let following = ["@dev", "@design", "@ios"]
 | 
				
			||||||
@ -47,9 +49,11 @@ struct ProfileTab: View {
 | 
				
			|||||||
                        )
 | 
					                        )
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: {
 | 
					                    RefreshableScrollView(
 | 
				
			||||||
                        fetchData()
 | 
					                        isRefreshing: $isRefreshing,
 | 
				
			||||||
                    }) {
 | 
					                        onRefresh: { fetchData() },
 | 
				
			||||||
 | 
					                        onScroll: onScroll
 | 
				
			||||||
 | 
					                    ) {
 | 
				
			||||||
                        VStack(spacing: 12) {
 | 
					                        VStack(spacing: 12) {
 | 
				
			||||||
                            header
 | 
					                            header
 | 
				
			||||||
                                .frame(maxWidth: .infinity)
 | 
					                                .frame(maxWidth: .infinity)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user