1 创建动态TableView

1.1 问题

动态表视图就是显示多少分区,多少行以及每一行的显示内容都是根据数据源来决定。之前我们学过用xib展示动态表视图,本案例将学习如何使用Storyboard展示动态表视图,如图-1所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-1

1.2 方案

首先创建一个SingleViewApplication项目,Xcode会自动帮我们创建好一个TRViewController类,并且自动带有Storyboard文件。将自动创建的TRViewController类删除,新建一个TRTableViewController类,继承至UITableViewController。

将Storyboard中自动生成的场景删除,从对象库拖拽一个表视图控制器对象,并被NavigationController包含。将TRTableViewController类和Storyboard中的表视图控制器进行关联。

然后将Storyboard中的Cell标识标记为“My Cell”,然后在TRTableViewController.m中回答三问,实现协议方法。

在cellForRowIndexPath方法中通过dequeueReusableCellWithIdentifier: forIndexPath:获取到的cell对象不会为空,Storyboard会自动帮助我们判断。

1.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建一个表视图控制器项目

创建一个SingleViewApplication项目,将自动创建的TRViewController类删除,新建一个TRTableViewController类,继承至UITableViewController。

再将Storyboard中自动生成的场景删除,从对象库拖拽一个表视图控制器对象,并被NavigationController包含。将TRTableViewController类和Storyboard中的表视图控制器进行关联,如图-2所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-2

最后选中Storyboard中的表视图控制器,在右边栏的检查器四种将表视图设置为动态,如图-3所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-3

步骤二:标记Cell,回答三问

选中Storyboard中TableView的Cell,在右边栏的检查器四中,将Identifier标识设置为“My Cell”,如图-4所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-4

在TRTableViewController.m文件中回答表视图的三问,cellForRowAtIndexPath协议方法中通过dequeueReusableCellWithIdentifier: forIndexPath:获取到的cell对象,不用再判断是否为空,因为Storyboard会自动帮我们进行判断,如果为空会自动创建一个cell对象,代码如下所示:

  1. -(NSInteger)tableView:(UITableView *)tableView
  2. numberOfRowsInSection:(NSInteger)section
  3. {
  4. return 10;
  5. }
  6. -(UITableViewCell *)tableView:(UITableView *)tableView
  7. cellForRowAtIndexPath:(NSIndexPath *)indexPath
  8. {
  9. UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"My Cell" forIndexPath:indexPath];
  10. cell.textLabel.text = @"Hello TableView.";
  11. return cell;
  12. }

1.4 完整代码

本案例中,TRTableViewController.m文件中的完整代码如下所示:

 
  1. #import "TRTableViewController.h"
  2. @implementation TRTableViewController
  3. - (NSInteger)tableView:(UITableView *)tableViewnumberOfRowsInSection:(NSInteger)section
  4. {
  5. return 10;
  6. }
  7. - (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPath *)indexPath
  8. {
  9. UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"My Cell" forIndexPath:indexPath];
  10. cell.textLabel.text = @"Hello TableView.";
  11. return cell;
  12. }
  13. @end

2 将xib中的自定义Cell案例移植到Storyboard

2.1 问题

本案例在Storyboard中自定义Cell,将网易新闻界面移植到Storyboard中,如图-5所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-5

2.2 方案

首先创建一个SingleViewApplication项目,Xcode会自动帮我们创建好一个TRViewController类,并且自动带有Storyboard文件。将自动创建的TRViewController类删除,新建一个TRTableViewController类,继承至UITableViewController。

将Storyboard中自动生成的场景删除,从对象库拖拽一个表视图控制器对象,并被NavigationController包含。将TRNewsTableViewController类和Storyboard中的表视图控制器进行关联。

其次创建一个TRNewsCell类继承至UITableViewCell,将Storyboard中的Cell与TRNewsCell绑定,并将cell的标识标记为“News Cell”。在cell的ContentView上拖放所需控件,给自定义Cell的界面添加视图,并将每个控件关联成TRNewsCell的输出口属性。

然后创建一个TRNews继承至NSObject,用于保存新闻的相关数据,本案例TRNews提供一组模拟新闻数据。

最后在TRTableViewController.m中回答三问,实现协议方法给表视图加载数据。

2.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建一个表视图控制器项目

创建一个SingleViewApplication项目,将自动创建的TRViewController类删除,新建一个TRNewsTableViewController类,继承至UITableViewController。

再将Storyboard中自动生成的场景删除,从对象库拖拽一个表视图控制器对象,并被NavigationController包含,并将导航栏的标题设置为“News“。

最后将TRNewsTableViewController类和Storyboard中的表视图控制器进行关联。

步骤二:自定义Cell

创建一个TRNewsCell类继承至UITableViewCell,在右边栏的检查器三中将Storyboard中的Cell与TRNewsCell绑定,如图-6所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-6

然后将cell的标识标记为“News Cell”。在cell的ContentView上拖放所需控件,给自定义Cell的界面添加视图,本案例拖放一个ImageView用来显示新闻图片、拖放三个Label分别用来显示新闻标题、新闻内容和新闻评论数目,如图-7所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-7

最后将Cell上的每个控件关联成TRNewsCell的输出口属性,代码如下所示:

 
  1. @interfaceTRNewsCell : UITableViewCell
  2. @property (weak, nonatomic) IBOutletUILabel *newsTitleLabel;
  3. @property (weak, nonatomic) IBOutletUILabel *newsDetailLabel;
  4. @property (weak, nonatomic) IBOutletUILabel *countLabel;
  5. @property (weak, nonatomic) IBOutletUIImageView *newsImageView;
  6. @end

步骤三:给表视图加载数据

创建一个TRNews继承至NSObject,用于保存新闻的相关数据,它有四个属性分别是NSString类型的title用于保存新闻的标题、NSString类型的detail用于保存新闻的详细内容、float类型的count用于保存新闻的评论数以及NSString类型的imageName用于保存新闻的图片名称,代码如下所示:

 
  1. @interfaceTRNews : NSObject
  2. @property (strong, nonatomic) NSString *title;
  3. @property (strong, nonatomic) NSString *detail;
  4. @property (nonatomic) float count;
  5. @property (strong, nonatomic) NSString *imageName;
  6. @end

本案例中TRNews还提供一个静态方法,用生成一组模拟新闻数据,代码如下所示:

 
  1. + (NSArray *)demoData
  2. {
  3. TRNews *n1 = [[TRNewsalloc]init];
  4. n1.title = @"苹果正式发布iPhone6/Plus";
  5. n1.detail = @"分别为4.7英寸和5.5英寸屏,均在9月19日正式开售。";
  6. n1.count = 5.5;
  7. n1.imageName = @"Apple Tree.ico";
  8. TRNews *n2 = [[TRNewsalloc]init];
  9. n2.title = @"首发地有香港无大陆";
  10. n2.detail = @"美国、加拿大、日本等首批上市,在美国才199美元,也就是1200人民币。";
  11. n2.count = 6;
  12. n2.imageName = @"Bliss.ico";
  13. TRNews *n3 = [[TRNewsalloc]init];
  14. n3.title = @"教师节快乐";
  15. n3.detail = @"老师我好想你,你教我的东西现在都还给你了,什么时候把学费还给我啊。";
  16. n3.count = 10;
  17. n3.imageName = @"Campfire.ico";
  18. TRNews *n4 = [[TRNewsalloc]init];
  19. n4.title = @"苹果正式发布iPhone6/Plus";
  20. n4.detail = @"分别为4.7英寸和5.5英寸屏,均在9月19日正式开售。";
  21. n4.count = 5.5;
  22. n4.imageName = @"City Night.ico";
  23. return @[n1, n2, n3, n4];
  24. }

最后在TRTableViewController.m中回答三问,实现协议方法给表视图加载数据,代码如下所示:

 
  1. -(NSInteger)tableView:(UITableView *)tableView
  2. numberOfRowsInSection:(NSInteger)section
  3. {
  4. returnself.news.count;
  5. }
  6. -(UITableViewCell *)tableView:(UITableView *)tableView
  7. cellForRowAtIndexPath:(NSIndexPath *)indexPath
  8. {
  9. TRNewsCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"News Cell" forIndexPath:indexPath];
  10. TRNews *news = self.news[indexPath.row];
  11. cell.newsTitleLabel.text = news.title;
  12. cell.newsDetailLabel.text = news.detail;
  13. cell.countLabel.text = [NSStringstringWithFormat:@"%g万", news.count];
  14. cell.newsImageView.image = [UIImageimageNamed:news.imageName];
  15. return cell;
  16. }

2.4 完整代码

本案例中,TRNewsTableViewController.m文件中的完整代码如下所示:

 
  1. #import "TRNewsTableViewController.h"
  2. #import "TRNews.h"
  3. #import "TRNewsCell.h"
  4. @interface TRNewsTableViewController ()
  5. @property (nonatomic, strong) NSArray *news;
  6. @end
  7. @implementation TRNewsTableViewController
  8. - (void)viewDidLoad
  9. {
  10. [superviewDidLoad];
  11. self.news = [TRNewsdemoData];
  12. }
  13. #pragma mark - Table view data source
  14. -(NSInteger)tableView:(UITableView *)tableView
  15. numberOfRowsInSection:(NSInteger)section
  16. {
  17. returnself.news.count;
  18. }
  19. -(UITableViewCell *)tableView:(UITableView *)tableView
  20. cellForRowAtIndexPath:(NSIndexPath *)indexPath
  21. {
  22. TRNewsCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"News Cell" forIndexPath:indexPath];
  23. TRNews *news = self.news[indexPath.row];
  24. cell.newsTitleLabel.text = news.title;
  25. cell.newsDetailLabel.text = news.detail;
  26. cell.countLabel.text = [NSStringstringWithFormat:@"%g万", news.count];
  27. cell.newsImageView.image = [UIImageimageNamed:news.imageName];
  28. return cell;
  29. }
  30. @end

本案例中,TRNewsCell.h文件中的完整代码如下所示:

 
  1. #import <UIKit/UIKit.h>
  2. @interfaceTRNewsCell : UITableViewCell
  3. @property (weak, nonatomic) IBOutletUILabel *newsTitleLabel;
  4. @property (weak, nonatomic) IBOutletUILabel *newsDetailLabel;
  5. @property (weak, nonatomic) IBOutletUILabel *countLabel;
  6. @property (weak, nonatomic) IBOutletUIImageView *newsImageView;
  7. @end

本案例中,TRNews.h文件中的完整代码如下所示:

 
  1. #import <Foundation/Foundation.h>
  2. @interfaceTRNews : NSObject
  3. @property (strong, nonatomic) NSString *title;
  4. @property (strong, nonatomic) NSString *detail;
  5. @property (nonatomic) float count;
  6. @property (strong, nonatomic) NSString *imageName;
  7. + (NSArray *)demoData;
  8. @end

本案例中,TRNews.m文件中的完整代码如下所示:

 
  1. #import "TRNews.h"
  2. @implementation TRNews
  3. + (NSArray *)demoData
  4. {
  5. TRNews *n1 = [[TRNewsalloc]init];
  6. n1.title = @"苹果正式发布iPhone6/Plus";
  7. n1.detail = @"分别为4.7英寸和5.5英寸屏,均在9月19日正式开售。";
  8. n1.count = 5.5;
  9. n1.imageName = @"Apple Tree.ico";
  10. TRNews *n2 = [[TRNewsalloc]init];
  11. n2.title = @"首发地有香港无大陆";
  12. n2.detail = @"美国、加拿大、日本等首批上市,在美国才199美元,也就是1200人民币。";
  13. n2.count = 6;
  14. n2.imageName = @"Bliss.ico";
  15. TRNews *n3 = [[TRNewsalloc]init];
  16. n3.title = @"教师节快乐";
  17. n3.detail = @"老师我好想你,你教我的东西现在都还给你了,什么时候把学费还给我啊。";
  18. n3.count = 10;
  19. n3.imageName = @"Campfire.ico";
  20. TRNews *n4 = [[TRNewsalloc]init];
  21. n4.title = @"苹果正式发布iPhone6/Plus";
  22. n4.detail = @"分别为4.7英寸和5.5英寸屏,均在9月19日正式开售。";
  23. n4.count = 5.5;
  24. n4.imageName = @"City Night.ico";
  25. return @[n1, n2, n3, n4];
  26. }
  27. @end

3 创建一个Universal项目

3.1 问题

我们在编程时如果希望一套代码兼容iPhone和iPad两个平台,那么在创建项目时Devices选项框就应该选择Universal,表示该程序兼容iPhone和iPad两个平台。本案例演示如何创建一个Universal项目,管理两个设备界面,如图-8、图-9所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-8

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-9

3.2 方案

首先创建一个SingleViewApplication项目,在项目选择窗口中的Devices选项框中选择Universal,表示该项目兼容iPhone和iPad两个平台。

在Xcode5以前,Universal项目会提供两个Storyboard文件,分别正对iPhone和iPad。从Xcode6开始IOS为我们提供了更新更简便的方式——多尺寸设计功能。

选中Storyboard文件中的场景,在右边栏的检查器一中确认Use Size Classes选项是否被勾上,在Xcode6中AutoLayout和SizeClasses是配合使用的。

然后将Xcode切换成分屏界面,在右边界面增加一个iPad界面,这样就能同时操作iPhone和iPad两个界面了。

最后通过在左边的设计窗口的下方的wAny和hAny选项来操作iPhone和iPad的界面,wAny和hAny是Xcode6提供的多尺寸设计功能工具。

3.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建Universal项目

首先创建一个SingleViewApplication项目,在项目选择窗口中的Devices选项框中选择Universal,表示该项目兼容iPhone和iPad两个平台,如图-10所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-10

选中Storyboard文件中的场景,在右边栏的检查器一中确认Use Size Classes选项是否被勾上,如图-11所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-11

步骤二:切换分屏窗口,添加iPad界面

在Xcode5以前,Universal项目会提供两个Storyboard文件,分别正对iPhone和iPad。从Xcode6开始IOS不再提供两个Storyboard文件,而是提供了一个多尺寸设计功能。

现将窗口切换成分屏界面,在右边设计界面上选择preview,然后选择Main.storyboard(Preview),如图-12所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-12

然后在右边设计界面的左下方,点击+号按钮,选择新增加一个iPad的画面,如图-13所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-13

新增完成后,可以在右边的画面中发现多了一個iPad的界面,如图-14所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-14

步骤三:通过wAny和hAny选项设置界面

在左边的设计窗口的下方,可以通过wAny和hAny选项来操作iPhone和iPad的界面,这是Xcode6提供的多尺寸设计功能,如图-15所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-15

当下方的设计面板是停在wAny和hAny的时候,下方的文字会提示目前是“For all layouts”,表示此时拖拽一個控制到界面中,那么iPhone和iPad的UI Layout上都会同时新增这个控件。拖拽一个Label控件到界面上,可以看到iPad和iPhone界面上都有一个同样的Label,如图-16所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-16

然后在iPhone界面添加一个Label,不需要在iPad界面上显示,此时就需要通过wAny和hAny工具调整界面,选择左边的两个方框会出现一行提示文字,提示Xcode只会将这个控件添加到符合尺寸的iDevice上,也就是iPhone,如图-17所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-17

最后在iPad界面添加一个Label,不需要在iPhone界面上显示,此时同样需要通过wAny和hAny工具调整界面,选择所有方框会出现一行提示文字,提示Xcode只会将这个控件添加到iPad上,如图-18所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-18

完成之后可以看到iPad和iPhone界面分别有一个不同显示内容的Label,如图-19所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-19

4 完成iPad的界面变换

4.1 问题

UISplitViewController控制器是一个控制器的控制器,是在iPad上构建导航模式应用的基础,可以呈现屏幕分栏视图的效果。本案例使用UISplitViewController控制器完成一个iPad的界面,通过选择左边栏的颜色能够修改右边界面的背景颜色,如图-20、图-21所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-20

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-21

4.2 方案

在创建好的项目中,将Storyboard文件中的场景删除,从对象库拖拽一个SplitViewController对象到界面中,系统提供的SplitViewController自带一个NavigationController(MastViewController)以及一个ViewController(DetailViewController),而NavigationController自带一个TableViewController作为根视图控制器,通常这个表视图控制器的作用类似导航栏。

其次创建两个类TRMasterViewController继承至UITableViewController,以及TRDetailViewController继承至UIViewController。这两个类分别和Storyboard中的MasterViewController和DetailViewController进行绑定。

然后在TRMasterViewController.m文件中实现表视图控制器的三问,给表视图加载数据。再通过实现协议方法didSelectRowAtIndexPath:完成修改右边界面的背景颜色功能,该方法中通过splitViewController.viewControllers属性获取到TRDetailViewController对象,由TRDetailViewController对象调用自己的更新界面方法来改变视图的背景颜色。

最后在Storyboard的DetailViewController场景中拖放一个Label控件,并将其关联成TRDetailViewController的私有属性label。

在TRDetailViewController类中公开声明并实现更新界面方法updateViewWithIndexPath:,该方法中通过indexPath参数修改背景颜色和label的显示内容。

4.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:在Storyboard中创建SplitViewController场景

在创建好的项目中,将Storyboard文件中的场景删除,从对象库拖拽一个SplitViewController对象到界面中,如图-22所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-22

可以从Storyboard界面中看到SplitViewController自带一个NavigationController(MastViewController)以及一个ViewController(DetailViewController),而NavigationController自带一个TableViewController作为根视图控制器,通常这个表视图控制器的作用类似导航栏,如图-23所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-23

步骤二:创建视图控制器,完成界面绑定

创建两个类TRMasterViewController继承至UITableViewController,以及TRDetailViewController继承至UIViewController。

TRMasterViewController和TRDetailViewController这两个类分别和Storyboard中的MasterViewController和DetailViewController场景进行绑定。

然后在TRMasterViewController.m文件中实现表视图控制器的三问,给表视图加载数据,代码如下所示:

 
  1. -(NSInteger)tableView:(UITableView *)tableView
  2. numberOfRowsInSection:(NSInteger)section {
  3. return 2;
  4. }
  5. -(UITableViewCell *)tableView:(UITableView *)tableView
  6. cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  7. UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
  8. if (indexPath.row==0) {
  9. cell.textLabel.text = @"Yellow Color";
  10. }else {
  11. cell.textLabel.text = @"Blue Color";
  12. }
  13. return cell;
  14. }

最后通过实现协议方法didSelectRowAtIndexPath:完成修改右边界面的背景颜色功能,该方法中通过splitViewController.viewControllers属性获取到TRDetailViewController对象,由TRDetailViewController对象调用自己的更新界面方法来改变视图的背景颜色,代码如下所示:

  1. -(void)tableView:(UITableView *)tableViewdidSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  2. //self.splitViewController.viewControllers属性获取到TRDetailViewController对象
  3. TRDetailViewController *vc = (TRDetailViewController*)[self.splitViewController.viewControllers lastObject];
  4. [vcupdateViewWithIndexPath:indexPath];
  5. }

步骤三:实现TRDetailViewController中的更新界面方法

首先在Storyboard的DetailViewController场景中拖放一个Label控件,并将其关联成TRDetailViewController的私有属性label,代码如下所示:

 
  1. @interfaceTRDetailViewController ()
  2. @property (weak, nonatomic) IBOutletUILabel *label;
  3. @end

然后在TRDetailViewController类中公开声明并实现更新界面方法updateViewWithIndexPath:,该方法中通过indexPath参数修改背景颜色和label的显示内容,代码如下所示:

 
  1. -(void)updateViewWithIndexPath:(NSIndexPath*)indexPath {
  2. if (indexPath.row==0) {
  3. [self.viewsetBackgroundColor:[UIColoryellowColor]];
  4. self.label.text = @"YellowColor";
  5. }else {
  6. [self.viewsetBackgroundColor:[UIColorblueColor]];
  7. self.label.text = @"BlueColor";
  8. }
  9. }

4.4 完整代码

本案例中,TRMasterViewController.m文件中的完整代码如下所示:

 
  1. #import "TRMasterViewController.h"
  2. #import "TRDetailViewController.h"
  3. @implementation TRMasterViewController
  4. -(NSInteger)tableView:(UITableView *)tableView
  5. numberOfRowsInSection:(NSInteger)section {
  6. return 2;
  7. }
  8. -(UITableViewCell *)tableView:(UITableView *)tableView
  9. cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  10. UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
  11. if (indexPath.row==0) {
  12. cell.textLabel.text = @"Yellow Color";
  13. }else {
  14. cell.textLabel.text = @"Blue Color";
  15. }
  16. return cell;
  17. }
  18. -(void)tableView:(UITableView *)tableView
  19. didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  20. TRDetailViewController *vc = (TRDetailViewController*)[self.splitViewController.viewControllers lastObject];
  21. [vcupdateViewWithIndexPath:indexPath];
  22. }
  23. @end

本案例中,TRDetailViewController.h文件中的完整代码如下所示:

 
  1. #import <UIKit/UIKit.h>
  2. @interfaceTRDetailViewController : UIViewController
  3. -(void)updateViewWithIndexPath:(NSIndexPath*)indexPath;
  4. @end

本案例中,TRDetailViewController.m文件中的完整代码如下所示:

 
  1. #import "TRDetailViewController.h"
  2. #import "TRMasterViewController.h"
  3. @interface TRDetailViewController ()
  4. @property (weak, nonatomic) IBOutletUILabel *label;
  5. @end
  6. @implementation TRDetailViewController
  7. -(void)updateViewWithIndexPath:(NSIndexPath*)indexPath {
  8. if (indexPath.row==0) {
  9. [self.viewsetBackgroundColor:[UIColoryellowColor]];
  10. self.label.text = @"YellowColor";
  11. }else {
  12. [self.viewsetBackgroundColor:[UIColorblueColor]];
  13. self.label.text = @"BlueColor";
  14. }
  15. }
  16. @end

5 使用内嵌视图显示内容

5.1 问题

UIPopoverController是iPad应用特有的类,不能再iPhone上使用,负责控制Popover视图。Popover视图是一种临时视图,它可以漂浮在视图表面,本案例使用PopoverController实现一个简易的文档菜单,如图-24所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-24

5.2 方案

首先Stroyboard文件中的场景嵌入NavigationController,在导航栏的左右两边分别拖放一个BarButtonItem,用于弹出Popover视图。

其次从对象库拖拽一个TableViewController控件的Stroyboard文件中,将表视图设置为静态视图,在Stroyboard中拖放好每个cell需要显示的控件和内容。

选中导航栏左边的按钮往表视图控制器上拉线,释放鼠标在弹出的窗口中选择popover presentation即完成popover视图的创建。

然后在Storyboard中再拖放一个TableViewController,此表视图设置为动态表视图,作为导航栏右边按钮弹出的popover视图。

另创建一个表视图控制类TRTableViewController,和刚才拖放的动态表视图控制器类进行绑定。在TRTableViewController类中回答表视图的三问给表视图加载数据,本案例中该表视图展示的是颜色选项。

最后将导航栏右边按钮关联成TRViewController的方法showPopover:,在该方法使用代码的方式创建另一个按钮的popover视图,并且弹出popover视图。

5.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:在Storyboard中创建popover视图

首先将Stroyboard文件中的场景嵌入NavigationController,在导航栏的左右两边分别拖放一个BarButtonItem,用于弹出Popover视图,如图-25所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-25

其次从对象库拖拽一个TableViewController控件的Stroyboard文件中,将表视图设置为静态视图,在Stroyboard中拖放好每个cell需要显示的控件和内容,如图-26所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-26

选中导航栏左边的按钮往表视图控制器上拉线,释放鼠标在弹出的窗口中选择popover presentation即完成popover视图的创建,如图-27所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-27

步骤二:使用代码创建popover视图

首先在Storyboard中另外再拖放一个TableViewController,将此表视图设置为动态表视图,作为导航栏右边按钮弹出的popover视图,并设置一个标识“popoverController”。

然后创建一个表视图控制类TRTableViewController,和刚才拖放的动态表视图控制器类进行绑定。在TRTableViewController类中回答表视图的三问给表视图加载数据,本案例中该表视图展示的是颜色选项,代码如下所示:

 
  1. -(NSInteger)tableView:(UITableView *)tableView
  2. numberOfRowsInSection:(NSInteger)section {
  3. returnself.data.count;
  4. }
  5. -(UITableViewCell *)tableView:(UITableView *)tableView
  6. cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  7. UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
  8. cell.textLabel.text = self.data[indexPath.row];
  9. return cell;
  10. }
  11. -(void)tableView:(UITableView *)tableViewdidSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  12. UITableViewCell *cell = [tableViewcellForRowAtIndexPath:indexPath];
  13. [cellsetAccessoryType:UITableViewCellAccessoryCheckmark];
  14. for (inti = 0; i<self.data.count; i++) {
  15. NSIndexPath *indexPath2 = [NSIndexPathindexPathForRow:iinSection:indexPath.section];
  16. UITableViewCell *cell2 = [tableView cellForRowAtIndexPath:indexPath2];
  17. if (cell2!=cell) {
  18. [cell2setAccessoryType:UITableViewCellAccessoryNone];
  19. }
  20. }
  21. }

最后将导航栏右边按钮关联成TRViewController的方法showPopover:,在该方法使用代码的方式创建另一个按钮的popover视图,并且弹出popover视图,代码如下所示:

  1. - (IBAction)showPopover:(UIBarButtonItem *)sender {
  2. TRTableViewController *tvc = [self.storyboardinstantiateViewControllerWithIdentifier:@"popoverController"];
  3. //创建POPover视图
  4. if (self.poc==nil) {
  5. self.poc = [[UIPopoverControlleralloc]initWithContentViewController:tvc];
  6. [self.pocsetPopoverContentSize:CGSizeMake(320, 220)];
  7. }
  8. //显示popover视图
  9. [self.pocpresentPopoverFromBarButtonItem:senderpermittedArrowDirections:UIPopoverArrowDirectionUpanimated:YES];
  10. }

最后完成效果如图-28所示:

故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期-LMLPHP

图-28

5.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

 
  1. #import "TRViewController.h"
  2. #import "TRTableViewController.h"
  3. @interface TRViewController ()
  4. @property (nonatomic,strong)UIPopoverController *poc;
  5. @end
  6. @implementation TRViewController
  7. - (IBAction)showPopover:(UIBarButtonItem *)sender {
  8. TRTableViewController *tvc = [self.storyboardinstantiateViewControllerWithIdentifier:@"popoverController"];
  9. if (self.poc==nil) {
  10. self.poc = [[UIPopoverControlleralloc]initWithContentViewController:tvc];
  11. [self.pocsetPopoverContentSize:CGSizeMake(320, 220)];
  12. }
  13. [self.pocpresentPopoverFromBarButtonItem:senderpermittedArrowDirections:UIPopoverArrowDirectionUpanimated:YES];
  14. }
  15. @end

本案例中,TRTableViewController.m文件中的完整代码如下所示:

 
  1. #import "TRTableViewController.h"
  2. @interface TRTableViewController ()
  3. @property (nonatomic,strong)NSArray *data;
  4. @end
  5. @implementation TRTableViewController
  6. -(NSArray *)data {
  7. if (!_data) {
  8. _data = @[@"Red",@"blue",@"Yellow",@"Pink",@"Purple",@"Gray",@"Black",@"Green"];
  9. }
  10. return _data;
  11. }
  12. - (NSInteger)tableView:(UITableView *)tableViewnumberOfRowsInSection:(NSInteger)section {
  13. returnself.data.count;
  14. }
  15. - (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPath *)indexPath {
  16. UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
  17. cell.textLabel.text = self.data[indexPath.row];
  18. return cell;
  19. }
  20. -(void)tableView:(UITableView *)tableViewdidSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  21. UITableViewCell *cell = [tableViewcellForRowAtIndexPath:indexPath];
  22. [cellsetAccessoryType:UITableViewCellAccessoryCheckmark];
  23. for (inti = 0; i<self.data.count; i++) {
  24. NSIndexPath *indexPath2 = [NSIndexPathindexPathForRow:iinSection:indexPath.section];
  25. UITableViewCell *cell2 = [tableView cellForRowAtIndexPath:indexPath2];
  26. if (cell2!=cell) {
  27. [cell2setAccessoryType:UITableViewCellAccessoryNone];
  28. }
  29. }
  30. }
  31. @end
05-02 16:43