当我们想要做一个界面类似 联系人 那样的程序时,就一定会用到 UITabBar,它可以帮我们添加、管理许多的Tab项, 使我们的程序包含不同的操作模式,由于管理UITabBar可能会有些麻烦,所以apple也帮我们对其进行了封装,产生了简单好用的UITabBarController,就像UITableViewController对UITableView的封装,只不过在用到UITabBarController时,我们不用像使用UITableViewController那样去继承它。
一、UITabBarController主要用来管理你提供的content view controllers,而每一个 content view controller则负责管理自己的view层级关系,通常,当你的程序想要提供一些平行(同一个等级的)的不同界面,而恰好这些界面使用到的数据是一类的,或者功能是一个系列的,那 tab bar interface 是非常有用的. 在这样的 tab bar interface界面中,你可以设置许多的 tab ,每一个 tab则一定要指定一个content view controller,当某个tab被点击时,UITabBarController就会选中该tab并且显示该viewController所持有的content view.在apple官网上有一张关于UITabBarController的图片,如下:
观察上图,最下面的那个Tab bar,这是由UITabBarController自己负责维护的,就像UINavigation Bar是由UINavigationController负责维护一样,不建议被修改,但如果实在需要改变的话,只能通过UITabBarController提供的方法去修改。
你有没有发现,绝大多数的iOS程序,如果他用到了UITabBarController,那么他的外观就像上图,Tab bar默认在下面,但有时我们又希望将他显示到最上面去,就像android的联系人程序一样,其实只要几句代码就行了:
CGRect frame = CGRectMake(0, 20, 320, 44) tabBarController.tabBar.frame = frame;
呵呵,这样不就可以了,你想放哪放哪,不过可别太难看了。
二、一个标准的 tab bar interface 通常由下列对象组成:
1.一个 UITabBarController 对象
2.每一个tab 都必须有一个content view controller(所以UITabBarController有一个属性是viewControllers)
3.一个可选的delegate对象
注意了:通常而言,UITabBarController一般作为应用程序的rootViewController,而且它不能作为UINavigationController的rootViewController.
所以初始化的代码一般这样写:
self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; ViewControllerA *A = [[ViewControllerA alloc]initWithNibName:@"ViewControllerA" bundle:nil]; ViewControllerB *B = [[ViewControllerB alloc]initWithNibName:@"ViewControllerB" bundle:nil]; ViewControllerC *C = [[ViewControllerC alloc]initWithNibName:@"ViewControllerC" bundle:nil]; ViewControllerD *D = [[ViewControllerD alloc]initWithNibName:@"ViewControllerD" bundle:nil]; ViewControllerE *E = [[ViewControllerE alloc]initWithNibName:@"ViewControllerE" bundle:nil]; UITabBarController *tabBarController = [[UITabBarController alloc]init]; A.tabBarItem = [[UITabBarItem alloc]initWithTabBarSystemItem:UITabBarSystemItemBookmarks tag:0]; self.viewController.tabBarItem = [[UITabBarItem alloc]initWithTabBarSystemItem:UITabBarSystemItemContacts tag:1]; B.tabBarItem = [[UITabBarItem alloc]initWithTabBarSystemItem:UITabBarSystemItemDownloads tag:2]; C.tabBarItem = [[UITabBarItem alloc]initWithTabBarSystemItem:UITabBarSystemItemHistory tag:3]; D.tabBarItem = [[UITabBarItem alloc]initWithTabBarSystemItem:UITabBarSystemItemSearch tag:4]; E.tabBarItem = [[UITabBarItem alloc]initWithTabBarSystemItem:UITabBarSystemItemTopRated tag:5]; tabBarController.viewControllers = @[self.viewController,A,B,C,D,E]; tabBarController.customizableViewControllers = @[B,C,D,E]; [tabBarController setSelectedIndex:2]; tabBarController.delegate = self; // CGRect frame = CGRectMake(0, 20, 320, 44); // tabBarController.tabBar.frame = frame; self.window.rootViewController = tabBarController;
你应该像上面那样,为每一个viewController指定一个tabBarItem,当然你也可以这样初始化
A.tabBarItem = [[UITabBarItem alloc]initWithTitle:<#(NSString *)#> image:<#(UIImage *)#> tag:<#(NSInteger)#>];
从而达到自定义tab bar item外观的目的,而不必使用系统提供好的,但此时你使用的图片大小要有规定了,一般ipad在60*60,iPhone在30*30左右,
再来看下面这张图,它描绘了UITabBarController和它的属性viewControllers、customizableViewControllers和selectedViewController等的关系
如果你的viewControllers属性添加了多于五个的items,那tab bar controller将会自动插入一个特殊的view controller,称为 More view controller,该 controller 将会负责管理多于的items,这个More view controller提供一个自定义的界面,用table的方式呈现多余的view controller,并且view controller的数量是不限制的。对于这个more view controller ,UITabBarController 通过一个属性----moreNavigationController持有它的引用,但看名字就知道他是一个UINavigationController对象,所有我们可以修改它的一些属性,如:
UINavigationController *nav = tabBarController.moreNavigationController;
[nav setNavigationBarHidden:YES];
当然,如不是必须,最好不要修改它。
三、在创建一个tab bar interface之前,你应该考虑清楚程序是否真的需要使用该布局,而且应该在正确的地方使用它……通常通过下面这些方式使用:
1.作为window的root view controller
2.作为 split view interface(iPad专有界面,不知道的可以百度下)中的其中一个一个view controller
3.作为modal view使用
4.作为UIPopoverController(iPad专有)的content view
四、在tab bar interface创建好后,我们可以用代码动态的修改它,如:增加或删除tab项,对于这种操作,通常我们需要重新指派UITabBarController的viewConrollers属性来进行,有人可能要问了,为什么要重新指派,viewController不是一个数组吗,不能直接通过数组的remove方法直接删除吗,可别忘了,这个属性的类型是个NSArray,不能进行删除,添加的。我们知道,当tab bar interface界面显示后,我们只能在某一时刻操作一个界面,因此,修改viewControllers属性必须在某个content viewController中完成,我们可以通过UIViewController的属性 tabBarController来获得UITabBarController的引用,就像获得UINavigationController的引用一样,修改代码如下:
NSMutableArray* newArray = [NSMutableArray arrayWithArray:self.tabBarController.viewControllers];
[newArray removeObject:self];
[self.tabBarController setViewControllers:newArray animated:YES];
五、当你点击某个tab项时,它对应的content viewController会得到显示,
但有时也许我们就是不希望某个被你点击的view得到显示,如:某个viewController所需的数据还没有完成加载,或者必须等某个登陆界面 完成登陆后
才能激活其他viewController,此时你可以实现UITabBarControllerDelgate中的方法
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController NS_AVAILABLE_IOS(3_0)
通过设置返回值来禁止某个viewController能否被选中,如下:
- (BOOL)tabBarController:(UITabBarController *)aTabBar shouldSelectViewController:(UIViewController *)viewController { if (![self hasValidLogin] && (viewController != [aTabBar.viewControllers objectAtIndex:0]) ) { // Disable all but the first tab. return NO; } return YES; }
当然你也可以通过代码手动去选择某个viewController,只要设置UITabBarController的属性selectedViewController 或者 selectedIndex(从0开始),但此时代理的方法是无效的,也就是说,如果你通过代码来选中某个viewController的话,则肯定是可以选中的。。。
六、其实UITabBarController还允许你对viewControllers进行排序,你可以使任意一个viewController出现在第一个tab项中,上面我们有提到moreNavigationController,当tabs超过5个时,也就是viewControllers的个数超过5个时,最后一个的tab item默认为more,然后那些没能显示在tab上的viewController便可通过moreNavigationController以列表的形势显示,那是不是那些没能在tab上显示的viewController就永远只能在moreNavigationController的列表中显示了??当然不是,当我么点击more tab时会出现下面左图的界面,然后再点击navigationBar左边的编辑按钮时会出现下面的右图,此时你可以把这些显示的tab直接拉到下面的 tab bar中,从而达到自定义tab的功能
那如果我希望某个viewController一直在tab上显示,二不希望用户将其排列到more tab中去,那该怎么办呢。。。。UITabBarController有个属性customizableViewControllers
由它来决定哪些viewController允许重排列。。不过这里要注意了,默认情况下customizableViewControllers 和 viewControllers属性包含的内容是一样的,你可以手动设置它为viewControllers的字集(只能是字集),但当你重新更新了viewControllers时,customizableViewControllers又会默认和viewControllers相等,希望表达清楚了。。。
七、
看看上面的图,是不是和应用程序的badge很像,当某个tab有信息需要你处理时,显示这个能很好的引起用户的注意,而你只需这样做
if (numberOfNewItems == 0) self.tabBarItem.badgeValue = nil; else self.tabBarItem.badgeValue = [NSString stringWithFormat:@"%d", numberOfNewItems];
self 是 viewContrller ,不过要注意了,这里的badgeValue是个NSString类型的,不要和下面的弄混了
[UIApplication sharedApplication].applicationIconBadgeNumber = 2
通常情况下,当我们点击显示了badge的那个tab后,这个红色的提示就应该消失。呵呵,可别忘了,当你切换tab时,viewController的声明周期可是一样的,它会执行那些
viewDidAppear 、viewDidDisappear等方法,所以最好的办法就是在该viewContrller的
-(void)viewDidAppear:(BOOL)animated方法中,将其重置为空,
如:self.tabBarItem.badgeValue = nil;
八、UITabBarController是否能旋转呢?那要看它的那些viewControllers了,如果在viewControllers中只要有一个viewController不支持某个方向的旋转,那UITabBarControlelr就也不能旋转到该方向。再来看看它的一些代理方法,我就简单描述下:
//当你选中某个tab 项时调用,我们可以在这里做一些操作,如隐藏状态栏,导航栏什么的。
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
//当点击more后出现moreNavigationController画面时,点击那个edit按钮时触发
- (void)tabBarController:(UITabBarController *)tabBarController willBeginCustomizingViewControllers:(NSArray *)viewControllers NS_AVAILABLE_IOS(3_0)
//下面两个方法在点击那个done按钮时触发
- (void)tabBarController:(UITabBarController *)tabBarController willEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed NS_AVAILABLE_IOS(3_0)
- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed