在iOS 7上,如果最终包含在标签栏控制器中,则使用工具栏推送控制器会留下无法使用的空间
在我的iOS应用程序中,我的窗口的rootViewController是一个标签栏控制器,其层次结构如下所示:
- 的UITabBarController
- UINavigationController 1
- FirstContentController
- UINavigationController 2
- …
- UINavigationController 3
- …
- …
- UINavigationController 1
当用户点击FirstContentController
上的某一行时, SecondController
一个实例将被推送到其导航控制器上。 SecondContentController
在其init
方法中设置hidesBottomBarWhenPushed
为YES
,并在viewWillAppear:
self.navigationController.toolbarHidden
设置为NO
。
在iOS 6中,用户将点击FirstController
的行,并将SecondController
推到导航控制器上。 因为它具有隐藏的hidesBottomBarWhenPushed
设置,它会隐藏标签栏,并且,当过渡animation完成时, SecondController
将在其工具栏可见的屏幕上。
但是,在iOS 7下testing时, hidesBottomBarWhenPushed
的行为似乎已经改变了。 我现在看到的是:
- 如预期的那样标签栏隐藏
- 按预期方式出现工具栏
- 在工具栏和内容视图之间会出现一个高度为49像素(标签栏高度)的不可用空间
差距是完全无法使用的 – 它不响应触摸,如果我在主视图上设置clipsToBounds
为YES,则没有任何绘制。 经过大量debugging和检查子视图层次结构后,iOS的自动调整机制将视图控制器视图的大小调整为411(在iPhone 5上)。 应该是460,直到工具栏,但布局系统似乎包括一个“鬼”49像素高的标签栏。
如果视图控制器有一个标签栏控制器作为一个,如果其父容器只会发生此问题。
在iOS 7上,如何在新控制器被按下时将标签栏消失,并且工具栏无缝滑入到位,并且仍然占用导航项和工具栏之间的整个空间?
UPDATE
经过进一步调查,只有当SecondController的edgesForExtendedLayout
设置为UIRectEdgeNone
才会发生这种情况。 但是,除非将该属性设置为UIRectEdgeNone
,否则该视图的框架太长,并且在工具栏下面延伸,无法看到或与之交互。
取消选中“隐藏底部酒吧推”,并设置您的自动约束,就好像有一个标签栏。 然后在控制器的“ViewDidLoad”中你想隐藏系统标签栏,把下面的代码。
[self.tabBarController.tabBar setFrame:CGRectZero];
这确保标签栏仍然接受用户交互,但对用户不可见。 (其他的select,如设置为0 alpha或隐藏将使标签栏无效)现在autoconstaraints将确保您的视图正确显示标签栏高度为零。
我发现,在SecondViewController的viewDidLoad
(在这里你想隐藏TabBar,但显示工具栏)添加以下2行代码修复了这个问题。
self.extendedLayoutIncludesOpaqueBars = YES; self.edgesForExtendedLayout = UIRectEdgeBottom;
我的viewDidLoad的SecondViewController如下:
- (void)viewDidLoad { [super viewDidLoad]; // These 2 lines made the difference self.extendedLayoutIncludesOpaqueBars = YES; self.edgesForExtendedLayout = UIRectEdgeBottom; // The usual configuration self.navigationController.navigationBar.barStyle = UIBarStyleBlack; self.navigationController.navigationBar.translucent = NO; self.navigationController.toolbarHidden = NO; self.navigationController.toolbar.barStyle = UIBarStyleBlack; self.navigationController.toolbar.translucent = NO; . . }
但是,您需要手动修复视图的框架,因为这会导致大小(320×504)。 这意味着它甚至延伸到工具栏后面。 如果这不是你的问题,那么这个解决scheme应该工作。
你不会喜欢这个答案这不是你想要的答案,但经过一些隐藏在iOS7的标签栏的研究,我的结论是: 不!
标签栏从来没有被隐藏 – 毕竟为什么有一个UITabBarController
如果你想隐藏标签栏。 隐藏底部hidesBottomBarWhenPushed
在视图控制器上隐藏导航控制器的底部栏,而不是选项卡栏。 从文档:
作为导航控制器的子项添加的视图控制器可以在屏幕底部显示可选的工具栏。 最上面的视图控制器上的这个属性的值确定工具栏是否可见。 如果此属性的值为YES,则隐藏工具栏 。 如果此属性的值为NO,则该栏可见。
此外,你被警告不要直接修改标签栏对象。 再次,从文档:
你不应该试图操纵存储在这个属性中的UITabBar对象本身。
这正是你把它设置为隐藏的时候正在做的。
在iOS6中这已经工作,但现在在iOS7中,它不。 而且似乎很容易将其隐藏起来。 当你最终设法隐藏它时,如果应用程序转到后台并返回,Apple的布局逻辑将覆盖您的更改。
我的build议是以模态方式显示你的数据。 在iOS7中,你可以创build自定义的转换,所以如果你有一个推动转换是重要的,你可以自己重新创build它,虽然这是有点超过顶部。 正常的模式转换是用户熟悉的东西,实际上它比隐藏标签栏的推送更适合这种情况。
另一个解决scheme是使用工具栏而不是标签栏。 如果您使用导航控制器的工具栏为您的选项卡,然后可以使用hidesBottomBarWhenPushed
作为您的要求,它会给你你期望的行为。
这是iOS 7 UIKit中的一个错误,由于以下特定的组合:
- 的UITabBarController
- hidesBottomBarWhenPushed = YES
- edgesForExtendedLayout = UIRectEdgeNone
- UINavigationController工具栏
您应该向Apple提交一个错误,并附上您的示例代码。
要解决该错误,您需要删除这四个条件之一。 两个可能的select:
-
修复您的“第二个”视图控制器的布局,以便当
edgesForExtendedLayout
设置为UIRectEdgeAll
时,它可以正常工作。 这可以像在滚动视图中设置contentInset
一样简单。 -
不要使用UINavigationController的内置工具栏。 相反,创build一个单独的UIToolBar实例并手动将其添加到您的第二个视图控制器的视图。
您必须将TabBarController
的tabBar
设置为hidden
并且您的视图应该将autosizing
设置为灵活的高度。
有了这个代码,它的工作:
@implementation SecondController -(id)init { if( (self = [super init]) ) { } return self; } - (void)viewDidLoad; { [super viewDidLoad]; self.view.backgroundColor = [UIColor redColor]; self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight; self.tabBarController.tabBar.hidden = YES; } -(void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // will log a height of 411, instead of the desired 460 NSLog(@"frame: %@", NSStringFromCGRect(self.view.frame)); } @end
或者,如果您确实想要使用hidesBottomBarWhenPushed
方法,则必须在显式推送视图控制器之前执行此操作:
-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { SecondController* controller = [[SecondController alloc] init]; controller.hidesBottomBarWhenPushed = YES; [self.navigationController pushViewController:controller animated:YES]; }
如果使用第二种方法,你的viewDidLoad方法可以摆脱灵活的高度方法以及tabBarHidden:
- (void)viewDidLoad; { [super viewDidLoad]; self.view.backgroundColor = [UIColor redColor]; self.edgesForExtendedLayout = UIRectEdgeNone; }
查看结果:
这个难题的关键是navigationcontroller.view.frame的大小不会改变。 这里的蝙蝠皮的要点是我自己的要点 。
FirstViewController.m
#import "FirstController.h" #import "SecondController.h" @implementation FirstController -(id)init { if( (self = [super init]) ) { self.tabBarItem.title = @"Foo"; self.tabBarItem.image = [UIImage imageNamed:@"Tab Icon.png"]; } return self; } -(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { return 1; } -(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; cell.textLabel.text = @"Click"; return cell; } -(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { SecondController* controller = [[SecondController alloc] init]; self.tabBarController.tabBar.hidden = YES; [self.navigationController pushViewController:controller animated:YES]; } @end
SecondViewController.m
#import "SecondController.h" @implementation SecondController -(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.view.backgroundColor = [UIColor redColor]; self.view.clipsToBounds = YES; /* ENTER VORTEX OF DESPAIR */ // without this, there's no gap, but the view continues under the tool // bar; with it, I get the 49-pixel gap thats making my life miserable self.edgesForExtendedLayout = UIRectEdgeNone; //this resizes the navigation controller to fill the void left by the tab bar. CGRect newFrame = self.navigationController.view.frame; newFrame.size.height = newFrame.size.height + 49; self.navigationController.view.frame = newFrame; /* EXIT VORTEX OF DESPAIR */ self.navigationController.toolbarItems = @[ [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:nil action:nil] ]; } -(void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; self.navigationController.toolbarHidden = NO; // will log a height of 411, instead of the desired 460 NSLog(@"frame: %@", NSStringFromCGRect(self.view.frame)); NSLog(@"frame: %@", NSStringFromCGRect(self.navigationController.view.frame)); } -(void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; self.tabBarController.tabBar.hidden = NO; self.navigationController.toolbarHidden = YES; //this resizes the navigation controller back to normal. CGRect newFrame = self.navigationController.view.frame; newFrame.size.height = newFrame.size.height - 49; self.navigationController.view.frame = newFrame; //this is optional and resizes the view to fill the void left by the missing toolbar. CGRect newViewFrame = self.view.frame; newViewFrame.size.height = newViewFrame.size.height + 49; self.view.frame = newViewFrame; } @end
如果您使用的是自动布局,请确保将视图固定到其超级视图,而不是“顶部布局指南”或“底部布局指南”。
你有没有试图移动你的电话hidesBottomBarWhenPDP在viewDidLoad或在secondViewController推之前?
使用ios7时,如果您不适时地打电话,会出现很多计时问题。
你提到你可以通过不触碰edgesForExtendedLayout
来解决这个edgesForExtendedLayout
。 是否有一个必要的原因,视图控制器的内容/控件包含在推视图控制器的根视图? 您可能会考虑将所有内容都包含在主视图的第一个也是唯一的子视图中。 然后在推送视图控制器的viewDidLayoutSubviews
中调整该视图的框架,以避免使用视图控制器的top / bottomLayoutGuide将内容永久置于工具栏下方。
我使用Gist构build了一个新项目,并将UITabBarController装入UINavigationController中:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; UITabBarController* tabController = [[UITabBarController alloc] init]; tabController.viewControllers = @[ [[UINavigationController alloc] initWithRootViewController:[[FirstViewController alloc] init]], [[UINavigationController alloc] initWithRootViewController:[[FirstViewController alloc] init]] ]; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tabController]; [navController setNavigationBarHidden:YES]; self.window.rootViewController = navController; return YES; }
并显示SecondViewController,这是我做了什么:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { SecondViewController* controller = [[SecondViewController alloc] init]; // Reaching the UITabBarViewController's parent navigationController [self.parentViewController.navigationController pushViewController:controller animated:YES]; }
最后,在第二个ViewController中:
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.view.backgroundColor = [UIColor redColor]; self.view.clipsToBounds = YES; // The following line only works in iOS7 if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) { self.edgesForExtendedLayout = UIRectEdgeNone; } [self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:nil action:nil]]; UIBarButtonItem * logoutButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemReply target:nil action:nil]; NSMutableArray * arr = [NSMutableArray arrayWithObjects:logoutButton, nil]; [self setToolbarItems:arr animated:YES]; [self.navigationController setNavigationBarHidden:NO animated:YES]; [self.navigationController setToolbarHidden:NO animated:YES]; } - (void)viewWillDisappear:(BOOL)animated { [self.navigationController setNavigationBarHidden:YES animated:YES]; [self.navigationController setToolbarHidden:YES animated:YES]; }
以下是它的外观:
编辑:改变了例子,并更改了截图。 制作了与iOS6兼容的示例。
我手动pipe理隐藏/取消隐藏的底部标签栏与淡入淡出的animation
... [self.tabBarController.tabBar setHidden:NO]; [self.tabBarController.tabBar setAlpha:0.1]; [UIView animateWithDuration:0.2 animations:^{ [self.tabBarController.tabBar setAlpha:1.0]; }]; ...
SecondVC上的底部工具栏已添加到IB中。 到目前为止没有问题。 使用故事板。
我想你可以将SecondController的edgesForExtendedLayout设置为UIRectEdgeBottom。
这有助于我:select你在故事板中查看控制器 – >转到属性 – >取消选中“调整滚动查看插图”
正如@Leo Natan指出的那样,似乎隐藏标签栏并显示工具栏是不鼓励的。 不过,有一个非常简单的解决scheme正在工作:
只需在故事板的视图控制器属性中选中“不透明的酒吧”,如下所示: