你的位置:首页 > 操作系统

[操作系统]iOS学习笔记——多控制器管理


NavigationController

在StoryBoard中添加NavigationController

在上网看到很多都是用xib添加,使用StoryBard的有两种办法,但我觉得下面用到那种方式比较好,直接在StoryBard中拖入一个NavigationController,在StoryBard中出现两个视图,一个是NavigationController,另一个是TableViewController。

TableViewController不是必要存在的,只是默认添加上去的,加入需要其他视图,则可以把它删除,重新拖入需要的视图,在NavigationController中按Ctrl键拖到新的视图中,这时弹出的Segue会比平常多了一项,它是属于RelationShip Segue分组的root view controller。

使用该Segue后,会发现第二个视图中出现了导航栏。把示意app启动引导的那个箭头拉到第一个视图,也就是NavigationController前面,

启动app会发现,app启动并非引导到NavigationController,而是后来新加的那个视图。在启动后打开的那个页面的导航栏中修改Title属性为"首页",那么往后我们也称这个页面为"首页",再往StoryBoard上面拖一个新的视图,在"首页"中添加一个Button按钮,给Button和新的页面建立Segue,类型选择为push,这个类型与往常用的Modal不一样,使用后原本空白的页面上多了导航栏和工具栏,然后在这个页面的导航栏中修改Title属性为"次页",保存运行一下,当点击Button跳转到次页的时候,发现导航栏多了一个后退的按钮,按钮上的文字也写明是"首页",故名思意就知道点击该按钮就能返回到"首页"了

 

 

NavigationItem添加

上面提到的后退按钮,其实是导航栏上面的一种导航栏元素,对于一个导航栏它会有LeftBarItem、RightBarItem、TitleView还有一个比较特殊的位于导航栏左边的BackBarItem。经本人尝试,如果一个导航栏上有BackBarItem和LeftBarItem,那么BackBarItem会被LeftBarItem覆盖,但这个有可能是本人尝试的范围有点窄,涵盖不了所有情况,按本人推断有可能是最后一个加到导航栏的就显示到导航栏上。那下面就演示一下单纯在导航栏上添加NavagationItem。

UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(selectLeftAction:)];self.navigationItem.leftBarButtonItem = leftButton; UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(selectRightAction:)];self.navigationItem.rightBarButtonItem = rightButton;

在上述代码中添加了左部按钮和右部按钮,两个按钮都被绑定了点击事件,调用不同的方法,如果点击后无操作则传入nil则可。效果如下

两个按钮的图标有所差别,这个在初始化方法的第一个参数所控制,其他值和图片分别如下表所示

  • UIBarButtonSystemItemAdd
  • UIBarButtonSystemItemCompose
  • UIBarButtonSystemItemReply
  • UIBarButtonSystemItemAction
  • UIBarButtonSystemItemOrganize
  • UIBarButtonSystemItemBookmarks
  • UIBarButtonSystemItemSearch
  • UIBarButtonSystemItemRefresh
  • UIBarButtonSystemItemStop
  • UIBarButtonSystemItemCamera
  • UIBarButtonSystemItemTrash
  • UIBarButtonSystemItemPlay
  • UIBarButtonSystemItemPause
  • UIBarButtonSystemItemRewind
  • UIBarButtonSystemItemFastForward
  • UIBarButtonSystemItemUndo
  • UIBarButtonSystemItemRedo

加入TitleView的代码如下所示

NSArray *array = [NSArray arrayWithObjects:@"元素1",@"元素2", nil];UISegmentedControl *segmentedController = [[UISegmentedControl alloc] initWithItems:array];segmentedController.segmentedControlStyle = UISegmentedControlSegmentCenter; [segmentedController addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged];self.navigationItem.titleView = segmentedController; 

 

这样程序运行起来就有一个分段控件在标题处

因为返回按钮是选择了push类型的Segue而自动生成的,而按钮上的文字都是自动添加上去的,加入要给这个按钮进行修改设置,单纯构造一个UIBarButtonItem赋值到self.navigationItem.backBarButtonItem属性上是不行的。因为这个self.navigationItem.backBarButtonItem并非本页面的返回按钮,实际是以本页面为起始页而导航到的下一页的返回按钮。引用一个网友的说法就是比如在AController跳转到BController,在A设置了self.navigationItem.backBarButtonItem,这个backBarButtonItem为BController的self.navigationController.navigationBar.backItem.backBarButtonItem。那么在要设置这个返回按钮则需要在HGNaviView1Controller中添加以下代码

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"根视图" style:UIBarButtonItemStyleDone target:self action:@selector(On_BackButton_Click)]; [self.navigationItem setBackBarButtonItem:backButton];

 

效果则如下图

在NavicationController中有两个属性是设置Bar Visibility,一个是设置导航栏的可视性;另一个设置工具栏的可视性。

同样也可以通过代码设置

[self.navigationController setToolbarHidden:false animated:true];

 

通过上面两种方式设置的结果都是全局的,凡是跟同一个NavigationController建立Segue的视图都会受影响。往工具栏上面添加按钮类似在导航栏上添加按钮,都是使用UIBarButtonItem,但添加到工具栏时是通过一个数组,代码如下所示

UIBarButtonItem *one = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:nil action:nil];UIBarButtonItem *two = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:nil action:nil];UIBarButtonItem *three = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:nil action:nil];UIBarButtonItem *four = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:nil action:nil];UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; [self setToolbarItems:[NSArray arrayWithObjects:flexItem, one, flexItem, two, flexItem, three, flexItem, four, flexItem, nil]];

 

当然ToolBar可以自行添加,但如果不把NavigationController统一建立的工具栏隐藏掉的话会导致视图上会有两个工具栏,假如只是个别页面需要显示工具栏的话个人还是觉得把NavigationController统一建立的工具栏隐藏,在需要的界面中自行添加工具栏

[self.navigationController setToolbarHidden:true animated:true];UIBarButtonItem *one = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:nil action:nil];UIBarButtonItem *two = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:nil action:nil];UIBarButtonItem *three = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:nil action:nil];UIBarButtonItem *four = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:nil action:nil];UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, self.view.frame.size.height - 44.0, self.view.frame.size.width, 44.0)];[toolBar setBarStyle:UIBarStyleDefault];toolBar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;[toolBar setItems:[NSArray arrayWithObjects: flexItem, one, flexItem, two, flexItem, three, flexItem, four, flexItem,nil]];[self.view addSubview:toolBar];

 

效果和上图完全一样

TabBarController

TabBarController使用

在使用过NavigationController之后使用TabBarController就容易上手了,在StoryBoard中拖入TabBarController,情况与NavigationController的类似,第一个页面TabBarController并非会呈现到用户界面中去,它只是起到一个管理各个子页面的效果,每个选项卡的具体内容会在他们的视图中编辑,这里默认会建立两个Tab,

如果需要再多的Tab,就可以直接拖入对应的ViewController,在TabBarController页面按Ctrl连接到新页面建立Segue,这里的Segue类型又有不同,Relationship Segue分组中有一个view controllers,就选择那个可以了,这样在TabBarController中会多加了一个Tab。

Tab修改

每个Tab的图标和文字都可以在相应的Tab视图中修改,

图标的尺寸是有限制的,在30*30,如果过大了就会有部分显示不出来,而且就算是给的图标是一个彩色的图片,最终显示在界面上的都只剩下一个轮廓,原图与显示在TabBar中的对比

在代码中同样可以用相应的属性对Tab的标题和图片进行设置

[self.tabBarItem setImage:[UIImage imageNamed:@"SunFlower.gif"]];[self.tabBarItem setTitle:@"第一选项卡"];

 

不过有另一个方法setFinishedSelectedImage:withFinishedUnselectedImage则可以把图标完整显示出来,如果图标过大则会占用下面文字的空间,而且图标会按原本的颜色显示出来,图标的显示还会按照选项卡的选中状态来决定

[self.tabBarItem setFinishedSelectedImage:[UIImage imageNamed:@"SunFlower.gif"] withFinishedUnselectedImage:[UIImage imageNamed:@"Ixia.gif"]];

 

选中时

未选中时

在每个TabBarItem中都有一个badgeValue属性,用于设置Tab的小红圈的值,他是NSString,所以可以给他赋的值就不局限在数字,还可是其他字符

self.tabBarItem.badgeValue=@"new";

 

Tab的数量可以无限地增加,但是在节目是最多可以显示五个Tab标签,如果Tab的数量多于5个的时候,原本第5个的Tab就会变成,并且点击进去是一个带TableView的导航页,从第5个开始的Tab会在TableView中显示,从TableView中导航到的Tab页都会带导航栏,以返回TabeView那一页

导航栏上面还有编辑按钮进入配置Tab的页面

在这一页中可以拖拽各个Tab标签到底部的TabBar中以更改Tab在TabBar中的顺序,而这里显示的Tab是可以通过UITabBarController的customizableViewControllers属性设定的,默认情况下它是和UITabBarController的viewController属性(这个就是UITabBarController拥有Tab的集合)拥有相同的元素,但是也可以通过设置把第6个Tab从customizableViewControllers中去除

NSArray *viewControllers= self.tabBarController.viewControllers;NSMutableArray *newViewControllers=[NSMutableArray arrayWithCapacity:viewControllers.count-1];for (int i=0; i<[viewControllers count]-1; i++) {  [newViewControllers addObject:[viewControllers objectAtIndex:i]];}self.tabBarController.customizableViewControllers=newViewControllers;

 

结果第6个Tab就不会出现在Configure页面中了

而对于viewControllers有的Tab而customizableViewControllers没有的Tab,则该部分Tab在编辑状态下不会被移除出TabBar。

关于选中的Tab

通过selectedIndex和selectedViewController都可以获取或设置被选中的Tab,对于设置selectedIndex和selectedViewController而言,仅仅能设置可以选中的Tab,并不能把页面切换过去,而且对于More这个Tab来说还有点特别的情况

  • 选中了More,selectedIndex是不能获取其准确的索引值,而selectedViewController可以获取到它的UITabBarItem;
  • 如果对selectedIndex赋上大于等于5的值,Tab就会选中More;
  • 如果对selectedViewController赋上tabBarController.moreNavigationController或者索引值大于或等于5的UITatBarItem,Tab就会选中More

UITabBarController的tabBar属性里面也可以通过selectedItem获取选中的UITabBarItem,但是并不能给这个selectedItem赋值,这回引发异常。虽然UITabBar有一些方法是可以改变自身状态,但不能给UITabBarController的tabBar修改自身状态。

UITabBarController的事件

UITabBarController拥有一些事件,通过这些事件可以监测Tab发生变化,这需要给ViewController实现UITabBarControllerDelegate协议,然后设置tabBarController的delegate属性

self.tabBarController.delegate=self;

 

事件归为两类,一类是单纯tabBar上Tab的选中状态发生变更前后出发的

-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController -(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController

 

 

先触发前者再触发后者,前者有一个布尔类型的返回值,如果返回的是False则会取消Tab的切换,但是通过代码设置SelectedIndex除外。两个参数tabBarController代表着起始的Tab,viewController代表着目标的Tab;

另一类是针对moreViewController的edit操作的

-(void)tabBarController:(UITabBarController *)tabBarController willBeginCustomizingViewControllers:(NSArray *)viewControllers -(void)tabBarController:(UITabBarController *)tabBarController willEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed -(void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed 

WillBegin…是在进入Edit界面时触发的,WillEnd…和didEnd….是在点击了Done之后相继触发的。