使用动画同时隐藏NavBar和TabBar

时间:2013-06-11 05:20:08

标签: objective-c cocoa-touch uitabbarcontroller core-animation

编辑:我向约翰颁发奖金,因为他在答案上付出了很多努力,无论如何都会得到它,但仍然没有可行的解决方案。我仍在寻找答案,如果有人知道如何做到这一点,我将不胜感激。

我想在我的应用中添加一个“最大化”按钮,隐藏导航和标签栏。导航栏和标签栏应平滑地滑入/滑出,内部/内容视图也应以与导航栏和标签栏相同的速率展开和缩小。

我使用[self.navigationController setNavigationBarHidden: YES/NO animated: YES];作为导航栏,发现此帖子How to hide uitabbarcontroller用于隐藏标签栏。

UITabBar类扩展:

- (void) setTabBarHidden:(BOOL)hidden animated:(BOOL)animated {
    CGRect screenRect = [[UIScreen mainScreen] bounds];

    float screenHeight = screenRect.size.height;
    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
        screenHeight = screenRect.size.width;
    }
    if (!hidden) {
        screenHeight -= self.tabBar.frame.size.height;
    }
    [UIView animateWithDuration: (animated ? UINavigationControllerHideShowBarDuration : 0) animations: ^{
        for (UIView* each in self.view.subviews) {
            if (each == self.tabBar) {
                [each setFrame: CGRectMake(each.frame.origin.x, screenHeight, each.frame.size.width, each.frame.size.height)];
            } else {
                [each setFrame: CGRectMake(each.frame.origin.x, each.frame.origin.y, each.frame.size.width, screenHeight)];
            }
        }
    } completion: ^(BOOL finished) {
        NSLog(@"Animation finished %d", finished);
    }];
}

问题是当我同时使用这两个(隐藏/显示导航和标签栏)时,它不干净。如果导航栏首先出现,锚定到底部的任何东西都会跳跃(参见下面的示例),如果标签栏首先出现,则顶部跳跃。

示例:我将UIButton置于右下角并设置其自动调整遮罩

resizeButton.frame = CGRectMake(self.view.bounds.size.width - 50, self.view.bounds.size.height - 100, 32, 32); // hardcoded just for testing purposes
resizeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;

但是当导航栏和标签栏最小化时,UIButton会在两种状态之间跳转(不会与标签栏一起滑动)。但是,如果我将其更改为附加到右上角,则它会与导航栏完美滑动。

有谁知道如何解决这个问题?


修改: 这是迄今为止我所拥有的壁橱和最优雅的解决方案(只是试图获得一个有效的概念):

[UIView animateWithDuration: UINavigationControllerHideShowBarDuration animations: ^{
    if (self.isMaximized) {
        self.tabBarController.view.frame = CGRectMake(0, 20, screenRect.size.width, screenRect.size.height + 49 - 20);
        [self.navigationController setNavigationBarHidden:YES animated:YES];
    } else {
        self.tabBarController.view.frame = CGRectMake(0, 20, screenRect.size.width, screenRect.size.height - 20);
        [self.navigationController setNavigationBarHidden:NO animated:YES];
    }
} completion: ^(BOOL finished) {
    NSLog(@"Frame done: %@", NSStringFromCGRect(self.view.frame));
    return;
}];

最大化:

  • 向上滑动导航栏,同时向下滑动标签栏
  • 内部/内容视图的顶部向上滑动,此视图的底部向下跳过

关于最小化:

  • 向下滑动导航栏,同时向上滑动标签栏
  • 内部/内容视图的顶部正确向下滑动,但底部跳转到最终值,留下空白,然后由滑动标签栏覆盖

如果我重新排列最小化动画的顺序(因此首先调用navbar animatino),那么内部/内容视图中的顶部会跳转

3 个答案:

答案 0 :(得分:7)

我使用的解决方案应该消除您看到的跳转问题。

此解决方案源自找到Carlos Oliva's github page的Objective-C类别,虽然该代码的版权是“保留所有权利”,但我写了他并且他提供了使用许可。

我的类别代码与他的代码略有不同。另外,在类别代码下面找到我在我的应用程序中使用的调用代码。

来自UITabBarController + HideTabBar.m

// the self.view.frame.size.height can't be used directly in isTabBarHidden or
// in setTabBarHidden:animated: because the value may be the rect with a transform.
//
// further, an attempt to use CGSizeApplyAffineTransform() doesn't work because the
// value can produce a negative height.
// cf. http://lists.apple.com/archives/quartz-dev/2007/Aug/msg00047.html
//
// the crux is that CGRects are normalized, CGSizes are not.

- (BOOL)isTabBarHidden {
    CGRect viewFrame = CGRectApplyAffineTransform(self.view.frame, self.view.transform);
    CGRect tabBarFrame = self.tabBar.frame;
    return tabBarFrame.origin.y >= viewFrame.size.height;
}


- (void)setTabBarHidden:(BOOL)hidden {
    [self setTabBarHidden:hidden animated:NO];
}


- (void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated {
    BOOL isHidden = self.tabBarHidden;
    if (hidden == isHidden)
        return;
    UIView* transitionView = [self.view.subviews objectAtIndex:0];

    if (!transitionView)
    {
#if DEBUG
    NSLog(@"could not get the container view!");
#endif
        return;
    }

    CGRect viewFrame = CGRectApplyAffineTransform(self.view.frame, self.view.transform);
    CGRect tabBarFrame = self.tabBar.frame;
    CGRect containerFrame = transitionView.frame;
    tabBarFrame.origin.y = viewFrame.size.height - (hidden ? 0 : tabBarFrame.size.height);
    containerFrame.size.height = viewFrame.size.height - (hidden ? 0 : tabBarFrame.size.height);
    [UIView animateWithDuration:kAnimationDuration 
                     animations:^{
                         self.tabBar.frame = tabBarFrame;
                         transitionView.frame = containerFrame;
                     }
     ];
}

来自我的ScrollableDetailImageViewController.m

- (void)setBarsHidden:(BOOL)hidden animated:(BOOL)animated
{
    [self setTabBarHidden:hidden animated:animated];
    [self setStatusBarHidden:hidden animated:animated];

    // must be performed after hiding/showing of statusBar
    [self.navigationController setNavigationBarHidden:hidden animated:animated];
}

- (void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated
{
    id parent = self.navigationController.parentViewController;
    if ([parent respondsToSelector:@selector(isTabBarHidden)]
        && hidden != [parent isTabBarHidden]
        && [parent respondsToSelector:@selector(setTabBarHidden:animated:)])
        [parent setTabBarHidden:hidden animated:animated];
}

答案 1 :(得分:-1)

只需尝试此代码,如果它正常工作。我在一年前写过这段代码。但是,它仍然适合我。

我没有使用基于块的动画。因为它是在我刚接触iOS时编写的。只需按照自己的意愿尝试优化自己。

- (void) hideTabBar:(UITabBarController *) tabbarcontroller {

    [self.navigationController setNavigationBarHidden:YES animated:YES];
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.1];
    for(UIView *view in tabbarcontroller.view.subviews)
    {
        if ([[UIDevice currentDevice]userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
            if([view isKindOfClass:[UITabBar class]])
            {
                [view setFrame:CGRectMake(view.frame.origin.x, 480, view.frame.size.width, view.frame.size.height)];
            } 
            else 
            {
                [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 480)];
            }            
        }else if([[UIDevice currentDevice]userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
            if([view isKindOfClass:[UITabBar class]])
            {
                [view setFrame:CGRectMake(view.frame.origin.x, 1024, view.frame.size.width, view.frame.size.height)];
            } 
            else
            {
                [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 1024)];
            }
        }
    }
    [UIView commitAnimations];
}

// Method shows the bottom and top bars

- (void) showTabBar:(UITabBarController *) tabbarcontroller {

    [self.navigationController setNavigationBarHidden:NO animated:YES];
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.1];
    for(UIView *view in tabbarcontroller.view.subviews)
    {
        if ([[UIDevice currentDevice]userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
            if([view isKindOfClass:[UITabBar class]])
            {
                [view setFrame:CGRectMake(view.frame.origin.x, 430, view.frame.size.width, view.frame.size.height)];
            } 
            else 
            {
                [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 436)];
            }            
        }else if([[UIDevice currentDevice]userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
            if([view isKindOfClass:[UITabBar class]])
            {
                [view setFrame:CGRectMake(view.frame.origin.x, 975, view.frame.size.width, view.frame.size.height)];
            } 
            else 
            {
                [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 980)];
            }
        }
    }
    [UIView commitAnimations]; 
}

答案 2 :(得分:-2)

试试这个

您可以使用以下动画隐藏标签栏控制器和导航栏: -

-(IBAction)hide:(id)sender
{
[self hideShowBars];
}
- (void) hideShowBars
{
   CGRect rect = self.navigationController.navigationBar.frame;
   CGRect rect1 = self.tabBarController.tabBar.frame;

   if(self.navigationController.navigationBar.isHidden)
    {
      [self.navigationController.navigationBar setHidden:NO];
      rect.origin.y=self.view.frame.origin.y;
    }
   else
   {
      rect.origin.y=self.view.frame.origin.y-rect.size.height;
   }

   if(self.tabBarController.tabBar.isHidden)
   {
      [self.tabBarController.tabBar setHidden:NO];
      rect1.origin.y=self.view.frame.size.height-rect1.size.height-rect1.size.height;
   }
   else
   {
      rect1.origin.y=self.view.frame.size.height;
   }
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.50];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(hideShowBarsAnimationStopped)];

self.navigationController.navigationBar.frame=rect;
self.tabBarController.tabBar.frame = rect1;
[UIView commitAnimations];
 }
- (void) hideShowBarsAnimationStopped
{
if(self.navigationController.navigationBar.frame.origin.y==self.view.frame.origin.y)
    return;

if(!self.navigationController.navigationBar.isHidden)
{
    [self.navigationController.navigationBar setHidden:YES];
}

if(!self.tabBarController.tabBar.isHidden)
{
    [self.tabBarController.tabBar setHidden:YES];
}
}