Search code examples
iosswiftuikitscrollviewcontentoffset

UINavigationBar Large Title doesn't appear when scroll view up


I have implemented a feature, when you press on a UITabBar icon and viewController1 scrolls up using its UIScrollView. It works perfectly, but if I scroll view down and stop somewhere, then switch to another viewController2, then get back to viewController1 and press tabBar icon - the viewController1 will scroll up, but Large Title will never be showed, and I should press tabBar icon one more time to show it:

The code I use for scroll up the VC1:

private var biggestTopSafeAreaInset: CGFloat = 0

    override func viewSafeAreaInsetsDidChange() {
        super.viewSafeAreaInsetsDidChange()
        self.biggestTopSafeAreaInset = max(view.safeAreaInsets.top, biggestTopSafeAreaInset)
    }
    
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        if tabBarController.selectedIndex == 0 {
            let navigationVC = viewController as? UINavigationController
            let firstVC = navigationVC?.viewControllers.first as? CurrencyViewController
            guard let scrollView = firstVC?.view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView else { return }
            
            if traitCollection.verticalSizeClass == .compact {
                scrollView.setContentOffset(CGPoint(x: 0, y: -view.safeAreaInsets.top, animated: true)
            } else {
                scrollView.setContentOffset(CGPoint(x: 0, y: -biggestTopSafeAreaInset, animated: true)
            }
        }
    }

I tried to track biggestTopSafeAreaInset in different stages of VC1 life, but it always has the same number - 196.0. But then why it doesn't scroll till the Large Title after viewControllers switch?


Solution

  • in your tableView set contentInsetAdjustmentBehavior to never

    tableView.contentInsetAdjustmentBehavior = .never
    

    in controller update the ui of navigation bar again

      override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            DispatchQueue.main.async { [weak self] in
                self?.navigationController?.navigationBar.sizeToFit()
            }
           
        }
    

    here is the navigation controller

    class BaseNavigationController: UINavigationController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            if #available(iOS 15.0, *) {
                let scrollAppearance = UINavigationBarAppearance()
                scrollAppearance.shadowColor = .white
                scrollAppearance.backgroundColor = .white
                let navigationBarAppearance = UINavigationBarAppearance()
                navigationBarAppearance.configureWithDefaultBackground()
                navigationBarAppearance.backgroundColor = .white
                navigationBarAppearance.largeTitleTextAttributes = [
                    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 26),
                    NSAttributedString.Key.foregroundColor: UIColor.black
                ]
                navigationBarAppearance.titleTextAttributes = [
                    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17),
                    NSAttributedString.Key.foregroundColor: UIColor.black
                ]
                UINavigationBar.appearance().backIndicatorImage = UIImage(named: "back-arrow")
                UINavigationBar.appearance().standardAppearance = navigationBarAppearance
                UINavigationBar.appearance().compactAppearance = navigationBarAppearance
                UINavigationBar.appearance().scrollEdgeAppearance = scrollAppearance
                navigationBar.tintColor = .black
                navigationBar.prefersLargeTitles = true
                navigationBar.isTranslucent = false
                navigationItem.largeTitleDisplayMode = .automatic
            } else {
                navigationBar.largeTitleTextAttributes = [
                    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 26),
                    NSAttributedString.Key.foregroundColor: UIColor.black
                ]
                navigationBar.titleTextAttributes = [
                    NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17),
                    NSAttributedString.Key.foregroundColor: UIColor.black
                ]
                navigationBar.tintColor = .black
                navigationBar.prefersLargeTitles = true
                navigationBar.isTranslucent = false
                navigationItem.largeTitleDisplayMode = .automatic
                navigationBar.barTintColor = .white
            }
            
        }
        
        override var preferredStatusBarStyle: UIStatusBarStyle {
            return .darkContent
        }
    
        
    }
    

    here is the Tabbar Controller

    class TabbarController:UITabBarController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            let c1 = C1()
            let c2 = C2()
            let c3 = C3()
            
            c1.tabBarItem = UITabBarItem(title: "Home", image: UIImage(named:  "home786"), tag: 0)
            c1.tabBarItem.tag = 0
            let nav1 = BaseNavigationController(rootViewController: c1)
            
            c2.tabBarItem = UITabBarItem(title: "Setting", image: UIImage(named:  "home786"), tag: 0)
            c2.tabBarItem.tag = 1
            let nav2 = BaseNavigationController(rootViewController: c2)
            c2.tabBarItem = UITabBarItem(title: "User", image: UIImage(named:  "home786"), tag: 0)
            c2.tabBarItem.tag = 2
            let nav3 = BaseNavigationController(rootViewController: c3)
            viewControllers = [nav1,nav2,nav3]
            selectedViewController = nav1
            tabBarController?.viewControllers?.first?.view.backgroundColor = .red
            
        }
    }