我的应用程序中有一个UITabBar
,我将其隐藏在第一个选项卡的第一个UIViewController
上,方法是将此行放在appDelegate:中
// ... in MyAppDelegate.m
firstViewController.hidesBottomBarWhenPushed = YES;
在firstViewController
中,用户可以在同一个选项卡中推送一个推送新UIViewController
的UIButton
。当这种情况发生时,我希望UITabBar
再次可见。我正试图让它像这样回来:
//... in firstViewController.m
secondViewController = [[SecondViewController alloc] init];
secondViewController.hidesBottomBarWhenPushed = NO;
[[self navigationController] pushViewController:secondViewController animated:YES];
不幸的是,没有带回UITabBar
。它仍然隐藏着。
隐藏UITabBar
后,如何正确地将其带到酒吧?
提前谢谢。
这是一个困扰我一段时间的问题,我刚刚找到了一个有效的解决方案。hidesBottomBarWhenPushed
属性是一个非常奇怪的野兽,在我看来,它以一种反直觉的方式工作。
它的问题是,当你按下一个新的视图控制器(或弹回(时,navigationController会询问所有视图控制器(从上到下(是否要隐藏底部栏,如果中的任何说YES
,则选项卡将被隐藏,这就是为什么尽管在新的视图控件上将NO
设置为隐藏,但选项卡仍保持隐藏的原因。
这是我的解决方案-覆盖视图控制器中您希望没有选项卡的hidesBottomBarWhenPushed
getter,并检查它是否位于堆栈的顶部:
Objective-C
- (BOOL) hidesBottomBarWhenPushed
{
return (self.navigationController.topViewController == self);
}
Swift(不太明显,因此为片段(
override var hidesBottomBarWhenPushed: Bool {
get {
return navigationController?.topViewController == self
}
set {
super.hidesBottomBarWhenPushed = newValue
}
}
这很好地将隐藏/显示逻辑封装在一个地方,所以您不必在执行隐藏的视图控制器之外考虑它。
这是hidesBottomBarWhenPushed
的文档所说的(增加了重点(:
如果是,则底部栏保持隐藏,直到视图控制器从堆栈中弹出
因此,看起来你所看到的行为正是文档所说的将要发生的事情。首先,将视图控制器推送到具有hidesBottomBarWhenPushed = YES
的堆栈上。此时,将其他视图控制器推到堆栈上不会改变底部栏的隐藏性。只要第一个视图控制器在堆栈上,底部栏就会保持隐藏状态。
所以我认为你必须想出一种不同的方法来实现你的UI目标。一种选择是将第一视图控制器作为模式视图控制器呈现在选项卡栏控制器的视图上。然后,当你想转到第二个视图控制器时,只需忽略第一个,瞧。唯一的视觉差异将是过渡动画。
当然还有其他选择,但这只是我第一个想到的。
祝你好运!
我遇到了同样的问题,但3小时后我找到了解决方案!在10月8日回答的这个话题中,Dave Batton说:
使用hidesBottomBarWhenPushed属性的正确方法是:
self.anotherViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:self.anotherViewController animated:animated];
不确定是否找到了解决方案,但我只是设法让它发挥作用。
我的场景:
我有一个UITabBarController
,有4个选项卡栏项目。在其中一个选项卡栏项目上,它加载了一个带有按钮的UIViewController
。按钮调用了一个IBOutlet
函数,该函数加载了另一个包含底部选项卡栏的UIViewController
。
经过多次试验&错误
在IBOutlet
函数上,我执行以下操作:
{
self.hidesBottomBarWhenPushed = YES;
/* Push the new controller with tab bar */
}
UITabBarController's
选项卡栏向左滑动,我的选项卡栏从按下的控制器向右滑动,这一切都很好。
显然,从功能的角度来看,当"返回"时,我需要将最初的UITabBarController's
tar条推回。
经过多次试验&错误
我在UIViewController
中有一个方法viewWillDisappear
,它推送带有选项卡栏的UIViewController
为:
- (void) viewWillDisappear:(BOOL)animated
{
self.hidesBottomBarWhenPushed = NO;
}
我在模拟器中对此进行了一些快速测试,它似乎运行良好。
一些贡献者认为这是一个糟糕的UI,但我现在正在尝试,看看结果如何。
很高兴收到(警察(任何反馈。:(
我认为您误解了隐藏底部工具栏的推送使用。如果是,则底部栏保持隐藏状态,直到视图控制器从堆栈中弹出。
所以,如果我正确理解你的问题:
第二个ViewController应为YES,第一个ViewController应该为NO。
我找到了一种非常简单的方法来通过子类化UINavigationController
来解决这个问题。你可以通过使用一个带有关联对象的类别来完成同样的事情,但我已经有了一个子类,所以我只是把代码放在那里。
首先,在UINavigationController:中添加一个ivar
@interface CustomNavigationController ()
{
NSMutableSet *_viewControllersWithHiddenBottomBar;
}
@end
然后我推翻了推送和弹出方法来接管隐藏逻辑的处理:
- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if(viewController.hidesBottomBarWhenPushed)
{
viewController.hidesBottomBarWhenPushed = NO;
[_viewControllersWithHiddenBottomBar addObject:viewController];
[self rootViewController].hidesBottomBarWhenPushed = YES;
}
else
{
[self rootViewController].hidesBottomBarWhenPushed = NO;
}
[super pushViewController:viewController animated:animated];
}
- (UIViewController *) popViewControllerAnimated:(BOOL)animated
{
if([_viewControllersWithHiddenBottomBar containsObject:self.viewControllers[self.viewControllers.count - 2]])
{
[self rootViewController].hidesBottomBarWhenPushed = YES;
}
else
{
[self rootViewController].hidesBottomBarWhenPushed = NO;
}
UIViewController *poppedViewController = [super popViewControllerAnimated:animated];
[_viewControllersWithHiddenBottomBar removeObject:poppedViewController];
return poppedViewController;
}
- (UIViewController *) rootViewController
{
return ((UIViewController *)self.viewControllers.firstObject);
}
我使用hidesButtomBarWhenPushed
属性来填充该集,然后在视图控制器级别重置该值(因为如果任何视图控制器都设置了该属性集,则其顶部的所有内容也将隐藏该属性(。为了使事情变得简单,我使用根视图控制器来控制根据集合中的值显示和隐藏选项卡。
您还需要在某个地方初始化集合,我刚刚使用了initWithRootViewController:
。
这对我来说非常无缝,是我能想到的最简单的方法,不需要接管任何现有的动画,也不需要处理边缘情况。
在中设置视图控制器
我不需要在选项卡栏中设置屏幕,这个设置屏幕在过去的两种方法和设置屏幕来推动任何屏幕在选项卡栏底部显示。
override func viewWillAppear(_ animated: Bool) {
self.hidesBottomBarWhenPushed = true
}
override func viewDidAppear(_ animated: Bool) {
self.hidesBottomBarWhenPushed = false
}
谢谢,如果你有任何疑问可以问。
这个对我有用。感谢其他线程中的提示,我找到了一个解决方案,只为一个视图cotroller隐藏选项卡栏,并为从内部调用的任何视图控制器重新建立它。
这样,我就可以保持常规的导航控制器链。
这就是我最终得到的:
#define kTabBarHeight 49 // This may be different on retina screens. Frankly, I have not yet tried.
- (void) hideTabBar:(BOOL)hide {
// fetch the app delegate
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
// get the device coordinates
CGRect bounds = [UIScreen mainScreen].bounds;
float width;
float height;
// Apparently the tab bar controller's view works with device coordinates
// and not with normal view/sub view coordinates
// Therefore the following statement works for all orientations.
width = bounds.size.width;
height = bounds.size.height;
if (hide) {
// The tab bar should be hidden too.
// Otherwise it may flickr up a moment upon rotation or
// upon return from detail view controllers.
[self.tabBarController.tabBar setHidden:YES];
// Hiding alone is not sufficient. Hiding alone would leave us with an unusable black
// bar on the bottom of the size of the tab bar.
// We need to enlarge the tab bar controller's view by the height of the tab bar.
// Doing so the tab bar, although hidden, appears just beneath the screen.
// As the tab bar controller's view works in device coordinations, we need to enlarge
// it by the tab bar height in the appropriate direction (height in portrait and width in landscape)
// and in reverse/upside down orientation we need to shift the area's origin beyond zero.
switch (delegate.tabBarController.interfaceOrientation) {
case UIInterfaceOrientationPortrait:
// Easy going. Just add the space on the bottom.
[self.tabBarController.view setFrame:CGRectMake(0,0,width,height+kTabBarHeight)];
break;
case UIInterfaceOrientationPortraitUpsideDown:
// The bottom is now up! Add the appropriate space and shift the rect's origin to y = -49
[self.tabBarController.view setFrame:CGRectMake(0,-kTabBarHeight,width,height+kTabBarHeight)];
break;
case UIInterfaceOrientationLandscapeLeft:
// Same as Portrait but add the space to the with but the height
[self.tabBarController.view setFrame:CGRectMake(0,0,width+kTabBarHeight,height)];
break;
case UIInterfaceOrientationLandscapeRight:
// Similar to Upside Down: Add the space and shift the rect. Just use x and with this time
[self.tabBarController.view setFrame:CGRectMake(0-kTabBarHeight,0,width+kTabBarHeight,height)];
break;
default:
break;
}
} else {
// reset everything to its original state.
[self.tabBarController.view setFrame:CGRectMake(0,0,width,height)];
[self.tabBarController.tabBar setHidden:NO];
}
return;
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
// It is important to call this method at all and to call it here and not in willRotateToInterfaceOrientation
// Otherwise the tab bar will re-appear.
[self hideTabBar:YES];
// You may want to re-arrange any other views according to the new orientation
// You could, of course, utilize willRotateToInterfaceOrientation instead for your subViews.
}
- (void)viewWillAppear: (BOOL)animated {
// In my app I want to hide the status bar and navigation bar too.
// You may not want to do that. If so then skip the next two lines.
self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
[self hideTabBar: YES];
// You may want to re-arrange your subviews here.
// Orientation may have changed while detail view controllers were visible.
// This method is called upon return from pushed and pulled view controllers.
return;
}
- (void)viewWillDisappear: (BOOL)animated {
// This method is called while this view controller is pulled
// or when a sub view controller is pushed and becomes visible
// Therefore the original settings for the tab bar, navigation bar and status bar need to be re-instated
[self hideTabBar:NO];
// If you did not change the appearance of the navigation and status bar in viewWillAppear,
// then you can skip the next two statements too.
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
return;
}
内联注释应解释每条语句的理由。不过,可能有更聪明的编码方法
隐藏状态栏和导航栏也有一个副作用,我不想对你们隐瞒。1.当从该导航控制器返回到呼叫导航控制器时,呼叫控制器上的状态栏和导航栏重叠,直到设备旋转一次,或者直到在另一个选项卡出现后再次选择相关选项卡。2.当调用视图控制器是表视图时,并且当设备返回到表时处于横向模式时,则表以横向的适当方向显示,但它被布置为纵向。左上角很好,但一些表格单元格和选项卡隐藏在屏幕下方。在右手边有一些空闲空间。这也是通过再次旋转设备来解决的。
一旦我找到了这些小但讨厌的错误的解决方案,我会随时向您更新。
使用
secondViewController.hidesBottomBarWhenPushed = NO;
插入一些操作时
firstViewController.hidesBottomBarWhenPushed = YES;