37

I want to hide a toolbar and nav bar as I scroll down a page. And return it as I scroll up. How is this possible?

How would I go about detecting the drag? Do I use pan gesture or is this down with the scrollview?

KAR
  • 3,199
  • 3
  • 25
  • 49
Lyndon King McKay
  • 637
  • 2
  • 7
  • 10
  • 1
    Possible duplicate of [Imitate iOS 7 Facebook hide/show expanding/contracting Navigation Bar](http://stackoverflow.com/questions/19819165/imitate-ios-7-facebook-hide-show-expanding-contracting-navigation-bar). Please scroll through the answers. There are Swift answers in there. – rmaddy Nov 18 '16 at 03:49

10 Answers10

102

Try this simple approach: Tested in Swift 3

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    if(velocity.y>0) {
        //Code will work without the animation block.I am using animation block incase if you want to set any delay to it.
        UIView.animate(withDuration: 2.5, delay: 0, options: UIViewAnimationOptions(), animations: { 
            self.navigationController?.setNavigationBarHidden(true, animated: true) 
            self.navigationController?.setToolbarHidden(true, animated: true)
            print("Hide")
        }, completion: nil)

    } else {
        UIView.animate(withDuration: 2.5, delay: 0, options: UIViewAnimationOptions(), animations: { 
            self.navigationController?.setNavigationBarHidden(false, animated: true)
            self.navigationController?.setToolbarHidden(false, animated: true)
            print("Unhide")
        }, completion: nil)    
      }
   }

Output: Updated

enter image description here

Note: If you passing any data from this VC to another VC that embedded with navigationController.You may need to unhide the NavigationBar.

Joe
  • 8,478
  • 8
  • 35
  • 56
  • 1
    Hi, this worked to hide it and unhide it, But how did you do to have the yellow part below the status bar? – Mago Nicolas Palacios May 10 '17 at 12:24
  • 1
    @MagoNicolasPalacios normally when you hide navigationBar.statusbar background goes transparent.I settled viewController background colour to yellow and tableview contentInset top padding to statusBar frame height(20px down). – Joe May 10 '17 at 12:35
  • Noob question I know. But where and how do you call this func? I mean where does velocity and targetContentOffset come from? Also, you place a Scroll View as the parent container, and table view inside of it? – Slobodan Antonijević Jun 01 '17 at 15:49
  • @SlobodanAntonijević thats your scrollView delegate. – GoodSp33d Nov 08 '17 at 09:54
  • 1
    @Joe Worked perfectly for me ! I shortened it to `self.navigationController?.setNavigationBarHidden(velocity.y > 0, animated: true)` as I had only nav bars to take care of ! – GoodSp33d Nov 08 '17 at 09:57
  • 2
    Good solution, however if you have long list and put finger to stop scroll navbar appears. A put "if else" clause where velocity.y < 0 - covers this case. Also I can't find how to fix a bug when tapping statusBar and scrollToTop activated - scrollViewWillEndDragging doesn't detect it. – odvan Nov 27 '17 at 16:09
  • @odvan what you described about the long list and finger issue is happening to me. What did you post in your "else if" clause? I tried self.navigationController?.setNavigationBarHidden(true, animated: false) but it's still showing the nav bar when I touch a cell – Lance Samaria Jul 15 '18 at 20:18
  • @Joe odvan's comment happened to me. i tried velocity.y>=0 but it did the exact opposite, once I put a finger to stop the scroll it hid the nav bar – Lance Samaria Jul 15 '18 at 20:36
  • This works for me if I completely remove self.navigationController?.setToolbarHidden(false, animated: true): in case I don't, when I go back from the detail view to the master, my layout gets completely messed up for unknown reasons – 3000 Feb 27 '19 at 12:43
  • @3000 May help. Read again the bottom *Note* in my answer. – Joe Feb 27 '19 at 13:01
  • @Joe: I did it in the viewWillAppear of the master VC but it didn't work. Maybe I should try on the back button tap. Another thing I must say: in my project, I did not want to hide the toolbar but the code doesn't hide it, for some unknown reason :-) – 3000 Feb 27 '19 at 13:05
  • @Joe: the toolbar thing didn' work because I had a tabBar, not a toolbar (in fact, if I reference the tab bar it works) :-) – 3000 Mar 01 '19 at 14:10
  • @3000 Toolbar is a subclass if tabBarController. Check the documentation. The code you looking for is something similar to “self.tabBarController?.setTabbarHidden(true, animated=true)”. – Joe Mar 01 '19 at 14:41
  • @Joe: in fact, I tried it before posting (setTabbarHidden doesn't exist, there's a boolean value isHidden you can use) :-) – 3000 Mar 01 '19 at 14:44
  • @Joe It will not work in the case when you take `UINavigationBar` in class – Nij Mar 26 '19 at 11:53
  • @Joe how to do when I have added UINavigationBar on view controller from storyboard itself? – Niraj Feb 24 '20 at 06:58
25

Easily to do this:

navigationController?.hidesBarsOnSwipe = true
Huu Phong Nguyen
  • 1,042
  • 10
  • 14
12

In my opinion the proper way to handle navigation bar in Tableview as follows. This would applicable if we have section header in Tableview.

func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
   if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0 {
      navigationController?.setNavigationBarHidden(true, animated: true)

   } else {
      navigationController?.setNavigationBarHidden(false, animated: true)
   }
}
rakeshNS
  • 4,157
  • 4
  • 26
  • 42
6

you can try self.navigationController?.hidesBarsOnTap = true in viewDidAppear also you can use hide on swipe.

saurabh
  • 6,543
  • 7
  • 40
  • 60
vivek agravat
  • 251
  • 2
  • 9
5

Thanks everyone, the way I went with was using AMScrollingController.

https://github.com/andreamazz/AMScrollingNavbar

It's updated for Swift 3

Lyndon King McKay
  • 637
  • 2
  • 7
  • 10
3

Swift 5 Xcode 10.3

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    navigationController?.hidesBarsOnSwipe = true
  }
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.hidesBarsOnSwipe = false
  }
Ahmed Abdallah
  • 2,193
  • 1
  • 17
  • 29
2

Here is very good option for that

Easily hide and show a view controller's navigationBar/tabBar as a user scrolls https://github.com/tristanhimmelman/HidingNavigationBar

import HidingNavigationBar

class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var hidingNavBarManager: HidingNavigationBarManager?
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        hidingNavBarManager = HidingNavigationBarManager(viewController: self, scrollView: tableView)
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        hidingNavBarManager?.viewWillAppear(animated)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        hidingNavBarManager?.viewDidLayoutSubviews()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

        hidingNavBarManager?.viewWillDisappear(animated)
    }

    //// TableView datasoure and delegate

    func scrollViewShouldScrollToTop(scrollView: UIScrollView) -> Bool {
        hidingNavBarManager?.shouldScrollToTop()

        return true
    }

    ...
}
BatyrCan
  • 5,755
  • 2
  • 12
  • 22
1

Swift UI

extension UINavigationController {
    override open func viewDidLoad() {
        super.viewDidLoad()
    hidesBarsOnSwipe = true
    // other customizations
    navigationBar.tintColor = .white
 }
}
keithics
  • 7,983
  • 2
  • 45
  • 32
0

I implemented this in my scrollview, as I was using components other than UITableView or UICollectionView, not sure if it works for you, but it's working perfectly for me:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let totalTop = (UIApplication.shared.statusBarFrame.size.height ?? 0) + (self.navigationController?.navigationBar.frame.height ?? 0)
    let shouldHideNavBar = scrollView.contentOffset.y > -(totalTop - 20) // 20 is an arbitrary number I added to compensate for some of scrolling
    navigationController?.setNavigationBarHidden(shouldHideNavBar, animated: true)
}
Septronic
  • 1,088
  • 12
  • 29
-5

You can use these lines of code :

- (void)scrollViewDidScroll: (UIScrollView *)scroll {
    // UITableView only moves in one direction, y axis
    CGFloat currentOffset = scroll.contentOffset.y;
    CGFloat maximumOffset = scroll.contentSize.height - scroll.frame.size.height;

    // Change 10.0 to adjust the distance from bottom
    if (maximumOffset - currentOffset <= 10.0) {
        self.navigationController?.hidden = YES;
    }
    else{
        self.navigationController?.hidden = NO;
    }
}
neha mishra
  • 364
  • 1
  • 11
  • 12
    The question is tagged Swift, not Objective-C. Please post answers in the appropriate language. – rmaddy Nov 18 '16 at 07:08
  • please use scrollViewWillEndDragging delegate method – midhun p Sep 14 '18 at 07:37
  • 1
    It helped.. I don't care it is answered under swift "tag". If its really care, why don't question those swift answers under every objective c "tags"??? Why? – Soorej Babu Jan 02 '20 at 08:07