一 StoryBoard简介
IOS
程序
开发
要遵循MVC的设计模式,为此苹果也提供了很多辅助的技术来让我们能够
更
好的更加快速的构建符合MVC模式的程序,Core Data可以给我们的M(数据模型)提供支持,而UIStoryboard可以为构建V(View)带了极大的便利。
StoryBoard封装了使用IB(interface builder)设计的视图,我们可以将一个程序的所有或部分视图结构关系放到一个storyboard中。
当我们的程序运行的时候,
StoryBoard运行时会根据我们的点击情况动态的加载相应的视图。
StoryBoard的本质是一个xml文件,他将我们用IB构建的视图关系持久化到了xml文件中,用xml文件来进行视图描述。学过Android开发的人应该知道,Android也是利用xml文件来描述用户设计的视图的。
二 StoryBoard的使用
使用StoryBoard一般都要指定一个根控制器,它作为该StoryBoard加载时的第一个需要显示的视图。
a. 直接拖动最左侧的小箭头
b. 勾选Is Initial View Controller的选项
2.关于UIStoryboardSegue
UIStoryboardSegue是链接两个场景用的,它是对场景切换的抽象,它主要封装了三个属性:
sourceViewController: 当前触发segue的控制器 源视图控制器
destinationViewController: 将要跳转到的控制器 目标视图控制器
identifier: 唯一标识segue,当我们触发一个segue的时候,该标识会被传递给source viewcontroller,这样我们就可以判断是哪个segue被触发了。
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(@"Source Controller = %@", [segue sourceViewController]);
NSLog(@"Destination Controller = %@", [segue destinationViewController]);
NSLog(@"Segue Identifier = %@", [segue identifier]);
if ([[segue identifier] isEqualToString:@"MyViewController"])
{
SecondViewController *viewController = [segue destinationViewController];
viewController.dataModel = ...
}
或者
if([[segue destinationViewController] class] == [MyViewController class])
{
MyViewController *myView = [segue destinationViewController];
。。。。。。
}
}
注意: 1.当两个视图控制器进行切换时,会自动的调用sourceViewController的- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender方法,如果我们想要添加自己的逻辑,例如向destinationViewController传递数据、判断当前哪个segue被出发了,就可以重载该方法。
3.在两个场景之间传递数据 Segue连接对象
当两个场景进行转换的时候,storyboard运行时 会创建一个segue对象,是UIStoryboardSegue的类。
当前源视图控制器会接收 prepareForSegue:sender: 消息,我们可以使用如下代码来向目标视图控制器传递数据:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// 判断启动的目标View是否为MyViewController
if([[segue destinationViewController] class] == [MyViewController class])
{
MyViewController *myView = [segue destinationViewController];
[myView setText:@"李宁"];
}
}
通过以上代码可以看到,在
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sende函数调用的时候,
目标视图控制器对象在Segue对象中已经被创建好了,所以可以把要传递的数据赋值给目标控制器
对象
的
属性,也可以通过调用目标控制器对象的方法来传递参数。
注意: 通过测试发现segue函数先于目标控制器的viewWillAppear 调用
4.设置默认启动的StoryBoard
在一个程序中,我们可以创建多个storyboard,但是需要指定一个 main storyboard,这样当程序启动的时候会自动的加载mai storyboard,其余的story board只能显式的进行加载了。
指定main storyboard
显式加载一个storyborad:
UIStoryboard* sb = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
NewViewController* newViewController = [sb instantiateViewControllerWithIdentifier:@"NewViewController"];
三 使用技巧
1.将入口由View变成了 UINavigationController
选中storyboard默认的View, 然后点击“Editor”>“Embed In”>“Navigation Controller”菜单项,XCode就会自动在storyboard上生成一个UINavigationController,并更改启动入口。
2.手动实现UIStoryboardSegue
为了在两个视图切换时候实现一些翻转特效,我们可以手动来实现自己的segue.
a.定义我们自己的Segue MyStoryboardSegue
第一个
@interface MyStoryboardSegue : UIStoryboardSegue
- (void)perform;
@end
@implementation MyStoryboardSegue
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
[UIView transitionWithView:src.navigationController.view duration:0.5
options:UIViewAnimationOptionTransitionNone
animations:^{
[src.navigationController pushViewController:dst animated:YES];
}
completion:NULL];
}
@end
第二个
#import <UIKit/UIKit.h>
@interface CustomModal : UIStoryboardSegue
- (void)perform;
@end
#import "CustomModal.h"
@implementation CustomModal
- (void) perform
{
UIViewController *current = self.sourceViewController;
UIViewController *next = self.destinationViewController;
[current presentViewController:next animated:YES completion:nil];
}
@interface CustomModal : UIStoryboardSegue
- (void)perform;
@end
@implementation CustomModal
- (void) perform
{
UIViewController *current = self.sourceViewController;
UIViewController *next = self.destinationViewController;
[current presentViewController:next animated:YES completion:nil];
}
@end
上面代码中我们定义了两个segue类。
手动实现一个segue很简单,我们只要继承UIStoryboardSegue类,然后重载-(void)perform方法,在该方法里面实现自己的逻辑就OK了。
b.在IB中使用自己定义的Segue
c.手动调用自己的segue
-(void) viewDidAppear:(BOOL)animated
{
//
调用模式视图的时候不能在viewDidLoad中进行调用
[self performSegueWithIdentifier:@"aabb" sender:self];
}
}
使用UIStoryboard还应该注意的问题:
1.孤儿View(独立于ViewController的View)是不能出现在StoryBoard里的,View必须通过ViewController来管理,StoryBoard更像是Controller对象的容器,而不是View对象的容器,NIB/XIB可以作为View对象的容器。
2.ViewController之间的过渡代码(-presentModalViewController:animated:和-pushViewController:animated:)已经是历史了,用StoryBoard可以直接可视化地连接不同的ViewController。
3.UIWindow对象的作用被进一步淡化,甚至可以这么说:其实很多程序根本无需用到UIWindow对象。AppDelegate也不再被鼓励(也不能)用来做ViewController--你甚至无法在Interface Builder的StoryBoard图上找到AppDelegate对象--因为它本来就不应该用来处理界面(View)的。(AppDelegate的作用很简单,就是处理UIApplication的回调,而不应该负责用户界面的处理,ViewController来负责处理View才是正确)
四 总结
StoryBoard是iOS 5的新特征,旨在代替历史悠久的NIB/XIB(其实StoryBoard还是基于NIB/XIB的,不过开发人员已经无需直接跟NIB打交道了)。
NIB文件也是用来描述用户界面的,NIB文件和ViewController相关联,他们是一对一的关系,使用NIB可以减少对界面的设计代码。而StoryBoard的出现,则是我们更加快速构建界面,整个程序的视图可以展现在一个storyboard中,可以作为程序的“设计图”来用,方便了我们对这个程序的视图结构的把握,而且使用storyboard的segue可以轻松的实现两个场景的跳转。
总之,使用Storyboard能够减少很多跟View相关的代码,使View和Controller进一步解耦,能够优化程序的“页面流”,让我们编写更加符合MVC模式的代码,使程序结构更加合理清晰。