How to hide tab bar when dragging like Safari app?
Asked Answered
I

6

11

I want to know how to implement an animation which hiding the tab bar when dragging downward, like Safari app on iOS 7. Any information from you will be appreciated.

Similar question: Show/hide UIToolbar, "match finger movement", precisely as in for example iOS7 Safari.

Inunction answered 16/11, 2013 at 3:35 Comment(3)
Try searching for custom control like what you want on cocoacontrols.com/controlsUltann
Thanks, I'm checking this now. cocoacontrols.com/search?utf8=%E2%9C%93&q=tabbarInunction
please ,so your code.Evolution
V
18

Something like this should work. I don't know if this gives exactly the same look as the Safari app, but it's close:

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (nonatomic) CGRect originalFrame;
@end

@implementation ViewController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, 1000);
    self.originalFrame = self.tabBarController.tabBar.frame;
}


-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    UITabBar *tb = self.tabBarController.tabBar;
    NSInteger yOffset = scrollView.contentOffset.y;
    if (yOffset > 0) {
        tb.frame = CGRectMake(tb.frame.origin.x, self.originalFrame.origin.y + yOffset, tb.frame.size.width, tb.frame.size.height);
    }
   if (yOffset < 1) tb.frame = self.originalFrame;
}
Venepuncture answered 16/11, 2013 at 5:23 Comment(6)
Thanks! It works! You and this site below helped me a lot. developers-life.com/…Inunction
I need same effect.But if it is UITableview How can I achieve this?need to do hide and show navigation bar and toolbarSterigma
UITableView extends UIScrollView so you can use the same method as aboveGula
Logically, this makes sense. But I'm not able to get it to work. The tab bar frame is always: {{0, 0}, {0, 0}}. Has anyone else run into this?Waist
@Venepuncture not completely work like safari, while yOffset decrease after increased at that time tabbar should appear.Scop
I think this is not the way it works in Safari; specifically, doesn't the tabbar show up again only when you scroll back to the top of the scrollview?Untried
R
8

The accepted answer doesn't work when you have a lot of cells in a table view -- The tab bar only shows up if you scroll all the way to the top.

I improved it like this:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, 1000);
    self.originalFrame = self.tabBarController.tabBar.frame;
}


-(void)scrollViewDidScroll:(UIScrollView *)scrollView{

UITabBar *tabBar = self.tabBarController.tabBar;

NSInteger yOffset = scrollView.contentOffset.y;
CGFloat yPanGesture = [scrollView.panGestureRecognizer translationInView:self.view].y;
CGFloat heightTabBar = tabBar.frame.size.height;

CGFloat tabBarOriginY = tabBar.frame.origin.y;
CGFloat frameHeight = self.view.frame.size.height;

if(yOffset>=heightTabBar)
    yOffset = heightTabBar;

// GOING UP ------------------
if(yPanGesture >= 0 && yPanGesture < heightTabBar && tabBarOriginY > frameHeight-heightTabBar){
    yOffset = heightTabBar - fabsf(yPanGesture);
}
else if(yPanGesture >= 0 && yPanGesture < heightTabBar && tabBarOriginY <= frameHeight-heightTabBar){
    yOffset = 0;
}
// GOING DOWN ------------------
else if(yPanGesture < 0 && tabBarOriginY < frameHeight){
    yOffset = fabsf(yPanGesture);
}else if(yPanGesture < 0 && tabBarOriginY >= frameHeight){
    yOffset = heightTabBar;
}
else{
    yOffset = 0;
}

if (yOffset > 0) {
    tabBar.frame = CGRectMake(tabBar.frame.origin.x, self.originalFrame.origin.y + yOffset, tabBar.frame.size.width, tabBar.frame.size.height);
}
else if (yOffset <= 0){
    tabBar.frame = self.originalFrame;
}
}

    - (void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{ 

// Handle unfinished animations   
    UITabBar *tabBar = self.tabBarController.tabBar;
    CGFloat yPanGesture = [scrollView.panGestureRecognizer translationInView:self.view].y;
    CGFloat heightTabBar = tabBar.frame.size.height;
    CGFloat tabBarOriginY = tabBar.frame.origin.y;
    CGFloat frameHeight = self.view.frame.size.height;


    if(yPanGesture > 0){

        if(tabBarOriginY != frameHeight - heightTabBar) {

            [UIView animateWithDuration:0.3 animations:^(void){
                tabBar.frame = self.originalFrame;
            }];

        }

    }else if(yPanGesture < 0){

    if (tabBarOriginY != frameHeight) {
        [UIView animateWithDuration:0.3 animations:^(void){
            tabBar.frame = CGRectMake(tabBar.frame.origin.x, frameHeight, tabBar.frame.size.width, tabBar.frame.size.height);
        }];
    }

}

}
Representationalism answered 28/3, 2015 at 23:45 Comment(3)
This is extremely glitchy looking on screen.Faithfaithful
Works perfectly for me! Although I didn't really need the scrollViewWillEndDragging bitBraswell
For me it worked fine. This should be the accepted answer.Andreaandreana
L
3

Honestly, I tried all these solutions and they weren't robust enough for me. They would hide the tab bar when it should have been showing, or they moved the tab bar up in a strange way.

I ended up spending the whole day trying to get them to work. I finally gave up and used: https://github.com/tristanhimmelman/HidingNavigationBar.

This gave me the functionality of hiding the nav bar and tab bar (which is what I really wanted in the first place). It works extremely well and I set it up in 10 minutes.

Hope this helps someone else not lose a day of coding to this :-0.

Logos answered 27/1, 2016 at 0:40 Comment(0)
I
1

You can use a variable to keep the lastContentOffset value. The key idea is tab bar origin.y is ranging between CGRectGetMaxY(screenRect) and CGRectGetMaxY(screenRect) - CGRectGetHeight(tabBarRect).

It works well in my project.

@interface ViewController ()
    @property (nonatomic, assign) CGFloat lastContentOffsetY;
@end

@implementation ViewController
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (!self.tabBarController) {
      return;
    }

  BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden;
  CGFloat kStatusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;

if (scrollView.contentOffset.y > (scrollView.contentSize.height - scrollView.frame.size.height)
    || (scrollView.contentOffset.y < (isStatsuBarHidden ? 0 : -kStatusBarHeight))) {
    // bottom & top bouncing - don't need to update
    return;
}

CGFloat offset = scrollView.contentOffset.y - self.lastContentOffsetY;
CGRect tabBarRect = self.tabBarController.tabBar.frame;
CGRect screenRect = [UIScreen mainScreen].bounds;

if (CGRectGetMaxY(tabBarRect) == CGRectGetMaxY(screenRect) + CGRectGetHeight(tabBarRect)) {
    //view could only scroll downward
    if (offset < 0) {
        tabBarRect.origin.y += offset;
    }
} else if (CGRectGetMaxY(tabBarRect) == CGRectGetMaxY(screenRect)) {
    //view could only scroll upward
    if (offset > 0) {
        tabBarRect.origin.y += offset;
    }
} else {
    //view could scroll upward & downward
    tabBarRect.origin.y += offset;
}

//safty reset handling
if (CGRectGetMaxY(tabBarRect) > CGRectGetMaxY(screenRect) + CGRectGetHeight(tabBarRect)) {
    tabBarRect.origin.y = CGRectGetMaxY(screenRect);
} else if (CGRectGetMaxY(tabBarRect) < CGRectGetMaxY(screenRect)) {
    tabBarRect.origin.y = CGRectGetMaxY(screenRect) - CGRectGetHeight(tabBarRect); // over bouncing, set it back
}

self.tabBarController.tabBar.frame = tabBarRect;
self.lastContentOffsetY = scrollView.contentOffset.y;
}
Inexplicable answered 7/10, 2016 at 13:32 Comment(0)
U
0

Well, while all the answers by others do neither work nor work partially, the HidingNavigationBar by @RobNorback works brilliantly, and it is in fact pretty easy to set up.

However, I have struggled a bit with the framework, and spent 2 hours fixing it, so I add my two cents for someone to not get in the same wrap.

If the number of items or rows in your collection view or table view is small, it does not hide the navbar (or tabbar or toolbar), even if the number of items or rows are large enough to go beyond the screen. You should add a bit more items or rows to make the framework correctly hide the bar.

Untried answered 11/5, 2016 at 16:49 Comment(0)
T
0
static CGFloat navBarOriginY = 20.0;

Create constant for base value of navigation bar origin Y position

- (void)viewDidLoad {
[super viewDidLoad];
 self.navigationController.hidesBarsOnSwipe = true;
[self.navigationController.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipe:)];
}

Add your custom selector to handle system swipe gesture that will fire before navBar become hidden and during hiding

- (void)swipe:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateFailed) {

If gesture state ended/canceled or failed you need entirely change frame of tabBar

    CGRect finalFrame = self.tabBarController.tabBar.frame;
    if (self.navigationController.navigationBar.frame.origin.y < 0) {
         //Tab bar will be hidden
        finalFrame.origin.y = self.maxTabBarY;
    } else {
         //Tab bar will be visible
        finalFrame.origin.y = self.minTabBarY;
    }

    [self setFrameForTabBar:finalFrame animationDuration:0.3];

} else if (recognizer.state == UIGestureRecognizerStateChanged) {

If state == changed than you need to pan your tabBar with navBar like in safari app.

    CGRect frame = self.tabBarController.tabBar.frame;
    CGFloat delta = navBarOriginY - self.navigationController.navigationBar.layer.presentationLayer.frame.origin.y;
    frame.origin.y = self.minTabBarY + delta;
    [self setFrameForTabBar:frame animationDuration:0.0];
} } }

- (void)setFrameForTabBar:(CGRect)frame animationDuration:(CGFloat)duration {
dispatch_async(dispatch_get_main_queue(), ^{
    [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
        self.tabBarController.tabBar.frame = frame;
    } completion:^(BOOL finished) {}];
});
Tridactyl answered 28/2, 2017 at 20:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.