现在,不管你点击 Menu 按钮多少次都没事了,任何时候只会有一个popover 显示。

除了 Popover segue,iPad 故事板还有 Replacesegue。用它,你可以替换 Split View Controller 中的 master 或 detail 窗口。以设置程序为例,master(左边)是一个Table View,它的每一行由是一个 detail view。你可以用 Replace segue 将每一行和它的 detail view 关联起来,每当你点击table view 中的一行,显示一个 detail 窗口。

segue 也可以以 UIModalPresentationFormSheet或者   UIModalPresentationPageSheet 风格呈现模式窗体,只需要设置目标 ViewController 的Presentation 属性即可:

译者注:

UIModalPresentationFullScreen代表弹出VC时,presentedVC充满全屏,如果弹出VC的wantsFullScreenLayout设置为YES的,则会填充到状态栏下边,否则不会填充到状态栏之下。

UIModalPresentationPageSheet代表弹出是弹出VC时,presentedVC的高度和当前屏幕高度相同,宽度和竖屏模式下屏幕宽度相同,剩余未覆盖区域将会变暗并阻止用户点击,这种弹出模式下,竖屏时跟UIModalPresentationFullScreen的效果一样,横屏时候两边则会留下变暗的区域。

UIModalPresentationFormSheet这种模式下,presentedVC的高度和宽度均会小于屏幕尺寸,presented VC居中显示,四周留下变暗区域。

UIModalPresentationCurrentContext这种模式下,presentedVC的弹出方式和presenting VC的父VC的方式相同。

这四种方式在iPad上面统统有效,但在iPhone和iPod touch上面系统始终已UIModalPresentationFullScreen模式显示presentedVC。

手动加载故事板

iPad 版还没有打分功能,我们可以将 iPhone 故事板中的 ViewController 添加到 Split-View 的 master 视图。从一个故事板中加载另一个故事板只能以编码的方式进行。

注意:我不建议你的在其他的 universal 应用中这样干。对于 universal app,应该始终让 iPhone 和iPad 的故事板保持分开。这里只是为了演示如何手动加载故事板,因为有时候你不得不在一个app 中加载多个故事板。

从 iPad 故事板中删除导航控制器和 Root ViewController。也可以删除 MasterViewController 类。 当前的故事板编辑器如下图所示:

我们会在 App Delegate 中加载 iPhone 故事板,把它的TabBarController 放到 split-view 的 Master 窗口中去。UIStoryboard 类负责呈现故事板。主故事板文件在应用程序启动时自动加载,如果你要加载额外的故事板,得调用

[UIStoryboard storyboardWithName:bundle:] 方法。

如果你想加载 iPhone 故事板,首先就得使用代码:

UIStoryboard*storyboard =
[UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];

由于我们的 app 是在 iPad 中运行的,它会去加载MainStroyboard~ipad 文件,这不是我们所期望的。

一般情况下你不会用代码去加载故事板,所以也没什么问题。但在这里,我们最好是重命名 MainStoryboard~ipad 文件。把它命名为“iPadMainStoryboard.storyboard”。

别忘了也要在 target 的 Summary 窗口中修改 iPadDeployment Info 小节中的 Main Storyboard 选项。最好 clean 一下以删除模拟器中的 app,确保清除缓存的故事板。

AppDelegate.m中修改 didFinishLaunchingWithOptions 方法:

- (BOOL)application:(UIApplication*)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

// ...existing code ...

UITabBarController *tabBarController;
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad)

{
tabBarController= (

UITabBarController*)self.window.rootViewController;

}else{

UISplitViewController *splitViewController=

(UISplitViewController *)self.window.rootViewController;

UIStoryboard*storyboard = [UIStoryboard storyboardWithName: @"MainStoryboard"bundle:nil];

tabBarController= [storyboard instantiateInitialViewController];

NSArray *viewControllers= [NSArray arrayWithObjects:tabBarController,
[splitViewController.viewControllers lastObject], nil];

splitViewController.viewControllers = viewControllers;

splitViewController.delegate = [splitViewController.viewControllers lastObject];

}

UINavigationController *navigationController= [[tabBarController viewControllers] objectAtIndex:0];

PlayersViewController *playersViewController= [[navigationController viewControllers] objectAtIndex:0];

playersViewController.players= players;

GesturesViewController *gesturesViewController= [[tabBarController viewControllers] objectAtIndex:1];

gesturesViewController.players= players;

return YES;

}

看这个地方:

UIStoryboard*storyboard = [UIStoryboard storyboardWithName: @"MainStoryboard"bundle:nil];

tabBarController =[storyboard instantiateInitialViewController];

这会加载 MainStoryboard 文件(iPhone 故事板)到新的UIStoryboard 对象中。然后通过 instantiateInitialViewController 方法加载它的第一个 ViewController,即我们的TabBarController。

拿到 TabBarController 之后,我们需要把它放到split-view 控制器中。当前 split-view 中只包含有 detail 视图,我们需要把 TabBarController 加到split-view 控制器的 viewControllers 数组中去:

NSArray*viewControllers = [NSArray arrayWithObjects: tabBarController,
[splitViewController.viewControllers lastObject], nil];

splitViewController.viewControllers = viewControllers;
运行程序,你可以看到在 split-view 的 popover 中显示了 iPhone 故事板中的内容:

如果你点击 Players 窗口中的内容,你会发现这种集成并不是十分的完美。因为在iPhone 的故事板中我们本来就没有为适应 iPad 屏幕而做过任何的配置。

在所有 ViewController 的 .m 文件中修改 shouldAutorotateToInterfaceOrientation方法为:

- (BOOL)shouldAutorotateToInterfaceOrientation:

(UIInterfaceOrientation)interfaceOrientation

{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

return YES;
return (interfaceOrientation!=

UIInterfaceOrientationPortraitUpsideDown);

}

现在,程序会正确地适应于横屏。但是,在 iPhone 故事板中,故事板编辑器不允许设置popover 窗口的大小(因为 iPhone 下没有 popover 控制器),因此我们得在代码中设置。在application:didFinish LaunchingWithOptions 方法中加入代码:

tabBarController.contentSizeForViewInPopover = CGSizeMake(320,460);

现在,split-view 弹出的 popover 正好与 iPhone 故事板中的ViewController 大小一致。

现在我们的程序有一个小问题,模式窗体会以全屏方式弹出,看起来有点怪异。这和 ViewController 的 modal presentation style 属性有关。如果在 prepareForSegue 方法中你使用了

navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;

则模式窗体就不会占据全屏了——它仅会填充 master 视图。

UIStoryboard 的 instantiateInitialViewController 方法并不是唯一的从故事板中加载ViewController 的方法。你可以用instantiateViewControllerWithIdentifier方法加载指定的 ViewController。如果在故事板中该 ViewController 并没有任何 segue,这个方法就很有用了。

让我们来演示一下。打开 iPhone 故事板,从 Players 中删除 EditPlayersegue。这个 segue 是被 disclosure 按钮所触发的。(提示:如果你现在运行程序,点击 disclosure 按钮,程序会崩溃并报告如下错误: "Receiver (<PlayersViewController>) has no seguewith identifier 'EditPlayer'")。

将 PlayersViewController.m 中的accessoryButtonTappedForRowWithIndexPath 方法修改为:

- (void)tableView:(UITableView*)tableView

accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath

{
UINavigationController*navigationController =

[self.storyboard instantiateViewControllerWithIdentifier: @"PlayerDetails"];

PlayerDetailsViewController *playerDetailsViewController= [[navigationController viewControllers] objectAtIndex:0];

playerDetailsViewController.delegate = self;
Player *player= [self.players objectAtIndex:indexPath.row];

playerDetailsViewController.playerToEdit = player;

[self presentViewController:navigationController animated:YES completion:nil];

}

这很像是我们曾经在 prepareForSegue 方法中所做的,除了这行:

UINavigationController*navigationController = [self.storyboard instantiateViewControllerWithIdentifier:

@"PlayerDetailsNavigationController"];

self.storyboard 属性引用了实例化该 ViewController 时所加载的 UIStoryboard 对象。我们用这个UIStoryboard 对象来实例化指定的 ViewController。这里即包含有玩家详情窗口的导航控制器。

要想让这行代码能正确工作,你必须在属性面板中设置该 ViewController的 identifier 属性。

运行程序(在模拟器中),编辑一个玩家。你会看到程序在没有 EditPlayersegue 的情况下仍然正常工作。

注意:我们要初始化的是导航控制器,因此设置 identifier 的时候设置的是导航控制器的 identifier 属性,而不是 PlayerDetailsViewController的 identifier 属性。

结束语

要本地化故事板是很容易的,如同本地化其他资源一样。选中故事板,在文件面板的Location 栏中增加新的语言,点击 Done。

现在,故事板中的每个 ViewController 都有一个列出顶层对象的dock 栏,一般都会包括 First Responder 以及该 ViewController。Gesture recognizer也会放在 dock上。理论上,你可以像在nib文件中一样,将任何对象拖到dock 上,但问题在于故事板编辑器无法编辑这些对象。

如果你想修改一个静态cell 的背景图片,你可以拖一个 UIImageView到 dock 上,然后将它连接到 cell 的 backgroundImage 属性。但你仅能通过面板编辑这个 ImageView,它不会被加到画布中。我希望故事板开发者能添加这个功能,因为这对于加载额外的对象很方便。

另外,你可以向故事板中放入标准的 ViewController 比如UIImagePickerController 和 MFMailComposeViewController。拖一个普通的ViewController ,然后将它的class 设置为 UIImagerPickerController 即可。在 prepareForSegue 方法里,设置 ViewController 的属性即可。我不太清楚故事板是否一直支持这种做法,但目前为止我还没有发现有什么问题;-)

iOS 5 故事板进阶(4)相关推荐

  1. 《iOS 9 开发指南》——第6章,第6.4节 Interface Builder中的故事板——Storyboarding...

    本节书摘来自异步社区<iOS 9 开发指南>一书中的第6章,第6.4节 Interface Builder中的故事板--Storyboarding,作者 管蕾,更多章节内容可以访问云栖社区 ...

  2. iOS开发那些事--创建基于故事板的iOS 6的HelloWorld

    基于故事板的HelloWorld工程 Storyboard(故事板)是用来替代xib的技术,也是iOS 5最重要的新特性之一.我们用Storyboard(故事板)重构HelloWorld. 使用故事板 ...

  3. ios标签控制器怎么用_带故事板的iOS标签栏控制器

    ios标签控制器怎么用 In this tutorial we'll look into another type of view controller namely Tab Bar Controll ...

  4. 《Swift iOS应用开发实战》——2.2 了解故事板

    本节书摘来自华章计算机<Swift iOS应用开发实战>一书中的第2章,第2.2节,作者:刘铭 著, 更多章节内容可以访问云栖社区"华章计算机"公众号查看. 2.2 了 ...

  5. [Xcode 实际操作]九、实用进阶-(23)多个Storyboard故事板中的页面跳转

    目录:[Swift]Xcode实际操作 本文将演示多个Storyboard故事板中的页面跳转. 使用快捷键[Command]+[N]创建一个新的故事板文件. (在项目文件夹[DemoApp]上点击鼠标 ...

  6. 在故事板中加载 nib 时 IBOutlet 为 nil

    故事板是在 iOS 5 开始出现的,在此之前我们使用的是 nib/xib.一个故事板支持多个 ViewController,同时可以在这些 ViewController 中进行连接(segue).但是 ...

  7. iOS安全入门与进阶

    清晨的西二旗是充满活力的,也是拥挤的.人来人往的地铁站前满是手持电话,拎着早点,迈着碎步追赶班车的西二旗er,当然,小i也不能免俗,左持蒸饺卤蛋豆腐脑,右提磨砂黑32G iphone 7(手机当然是背 ...

  8. Silverlight Blend动画设计系列五:故事板(StoryBoards)和动画(Animations)

    原文:Silverlight & Blend动画设计系列五:故事板(StoryBoards)和动画(Animations) 正如你所看到的,Blend是一个非常强大的节约时间的设计工具,在Bl ...

  9. 什么是故事板?(故事图、Storyboard)(软件显示效果的视觉草图,用于视频创作和广告设计,表达作者的创意)

    故事板是软件显示效果的视觉草图,用于视频创作和广告设计,表达作者的创意.20世纪90年代以来,电脑绘制软件渐渐取代了过去的手绘故事板,许多大制作的商业影片,都在拍摄之前用电脑动画模拟的方式创建故事板, ...

  10. 【WPF学习】第五十章 故事板

    正如上一章介绍,WPF动画通过一组动画类(Animation类)表示.使用少数几个熟悉设置相关信息,如开始值.结束值以及持续时间.这显然使得它们非常适合于XAML.不是很清晰的时:如何为特定的事件和属 ...

最新文章

  1. lua 开发环境搭建(windows 平台)
  2. python控制台颜色输出以及字符串格式化输出
  3. webpack学习笔记 (三) webpack-dev-server插件和HotModuleReplacementPlugin插件使用
  4. Spark _10_补充部分算子【三】
  5. 老司机带你重构Android的v4包的部分源码
  6. 的udp的接收端如何看速率_计算机网络 TCP与UDP
  7. Java获取文件的目录_Java获取文件目录(路径)的方式
  8. 通过CN3口直接控制台达伺服电机A2-M(三)
  9. Java使用Lambda表达式多字段求和
  10. 一起聊一聊数字化,信息化,数据化,数字化转型(建议收藏)
  11. 缓存击穿和雪崩常用解决方案
  12. EVG实现芯片到晶圆的融合和混合键合
  13. 一级计算机能用计算器吗,中级会计师考试机考可以用电脑上的计算器吗?
  14. 计算机人工智能分数,分数一般想学人工智能?这6所双一流大学是首选
  15. 通识1——网络摄像机简介
  16. 战术小队虫族服务器进去后不显示,【星际争霸】飞龙在天——虫族飞龙使用完全手册...
  17. IE和火狐的css兼容性问题
  18. 怎么实现全国IP自动更换?
  19. firefox附加组件开发者指南(三)——XUL简介(下)
  20. 通过数据表的DataSet输出XML做数据比对

热门文章

  1. 用微信公众号写博客就是玩,要动真格的还是得WordPress!
  2. 给IT新人的15点建议
  3. 计算机cpu风扇不转怎么办,组装电脑cpu风扇不转怎么办 组装电脑cpu风扇不转解决方法【介绍】...
  4. 红米手机开启开发者模式方法
  5. 中兴网络机顶盒-ZXV10 B860AV1.1-t装第三方软件实现直播
  6. 即使最平凡的人,也有不妥协的一面
  7. 35岁仍然落魄,有这3个苗头将大器晚成,你要刮目相看,主动结交
  8. python编程考试_Python编程练习(一)
  9. R语言导入TXT数据,最简单明了!!!
  10. 带省略号的比喻句_标点符号往往能引发人们的联想,例如:“省略号像一条漫长的人生道路,等着你去书写它留下的空白。”请以一种标点符号(省略号除外)为描述对象,写一个比喻句,形象地阐发某种生活道理。...