您的位置:首页 > 其它

一百、创建 基于页面视图控制器的应用程序

2012-10-31 09:59 302 查看
在Xcode当中 创建 基于页面控制器的应用程序时,我们 有 一个选择 就是 利用 Xcode提供的基于页面的应用程序模板。当我们 选择 基于页面的应用程序模板后,Xcode 会生成 一个用12个页面显示一年中各个月份的应用程序。这个模板 使 人 感到 很奇怪,因为 这个模板所提供的 不仅是 一个我们在其之上创建应用程序的基础 而 相当于是 一个示例程序了。虽然 这 对于最初的学习 很有用,但是 除非 在12个页面上写上12个月的名称 正好 是 你所需要的,否则
我们 必须把 多余的功能 去除,然后 才能用于 其它用途。

与其选择 Xcode提供的基于页面的应用程序模板,我们 在这篇博文中 要选择 单视图应用程序模板 并且 在其之上 实现 页面功能。


创建 项目

我们 启动 Xcode 并且 创建 一个新的iOS单视图应用程序。我们 将 这个应用程序的产品名称 和 物件类型名称前缀 设定为 pageApp。我们 还要确保 使用故事板(Use Storyboard)选项 没有被选择。


添加 内容视图控制器

在这里这个例子当中 我们 要使用 一个视图控制器物件 向用户 展示 页面。这个视图控制器中的视图上 会包含 一个网页视图物件(UIWebView类型) 根据当前的页数 显示出 不同的html内容。另外 这个视图控制器物件 还需要 另外一个物件 来容纳 需要显示的html内容。

为了添加 这个视图控制器,我们 需要创建 一组Objective-c Class文件。创建 新的Objective-c Class文件时,将 Class选项 填写为 ContentViewController 并且 确保选择了 With XIB for user interface这个选项。

选择 ContentViewController.h这个文件 并且 将 这个文件 修改为 这样:

123456789#import <UIKit/UIKit.h>@interface ContentViewController : UIViewController@property (strong,nonatomic) IBOutlet UIWebView *webView;@property (strong,nonatomic) id dataObject;@end
这样一来 每个ContentViewController类型的物件 都包含 一个网页视图物件webView 和 一个任意类型的数据物件dataObject。接着 打开 ContentViewController.xib这个文件 再 从物件库中 拖 一个网页视图(Web View) 放 到画布中的视图上。然后 按住 键盘上的control键 并且 用 鼠标 点住 File’s Owner图标 不放。再 将 鼠标光标 拖到 画布中的网页视图上 并且 放开 鼠标。最后 在弹出来的菜单中 选择 webView这个选项。每次用户 在应用程序中 翻页时,适用于UIPageViewController类型物件的一项措施 都会得以实施 从而创建 一个新的ContentViewController类型的物件 并且 将 正确的html内容 存储 在这个ContentViewController物件所包含的数据物件dataObject当中 以便 网页视图物件webView 显示出来。而 在ContentViewController类型的物件所包含的视图 显示出来之前,适用于ContentViewController这类物件的措施viewWillAppear: 会得以执行,于是 我们 要在viewWillAppear:这项措施中 将 数据物件dataObject中的内容 存储 在网页视图物件webView当中。所以 我们 打开 ContentViewController.m这个文件 并且 在@implement命令之后 加入

1

@synthesizewebView,dataObject;

这行语句,用以生成 webView、setWebView: 和 dataObject、setDataObject:这四项措施。

同时 还要在这个文件中 加入 viewWillAppear这项措施:

123456789-(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self.webView loadHTMLString:self.dataObject baseURL:[NSURL URLWithString:@""]];}
到目前 为止,我们 已经设计好了 内容视图控制器。下一步 我们 要设计 应用程序的数据模型。

创建 数据模型

这个应用程序的数据模型 由一个数组物件 构成,这个数据物件 包含 若干个字符串物件,其中 每个字符串物件 都是 需要显示在各个页面上的html内容。在我们这个例子当中 我们 把pageAppViewController类型的物件 用作 页面视图控制器的数据源。同时 由于这个原因 pageAppViewController这类物件 必须遵循 UIPageViewControllerDataSource这项协议,所以 我们 打开 pageAppViewController.h这个文件 并且 将 @interface这行语句 修改成 这样:

1

@interfacepageAppViewController:UIViewController<UIPageViewControllerDataSource>

以表明 pageAppViewController这类物件 遵循 UIPageViewControllerDataSource这项协议。除此之外 我们 需要在@interface命令 和 @end命令之间 加入 这两行语句:

123@property (strong,nonatomic) UIPageViewController *pageViewController;@property (strong,nonatomic) NSArray *pageContent;
这样 每个pageAppViewController类型的物件 都会包含 一个页面控制器物件pageViewController 和 数组物件pageContent。其中 数组物件pageContent 用来存储 各个页面的html内容。同时 不要忘了 在pageAppViewController.m这个文件中的@implementation命令后 加入

1

@synthesizepageViewController,pageContent;

接着 我们 要编写 一项适用于pageAppViewController这类物件的措施createContentPages:

12345678910111213141516171819-(void)createContentPages{ NSMutableArray *pageStrings=[[NSMutableArray alloc] init]; for(int i=1;i<11;i=i+1) { NSString *contentString=[[NSString alloc] initWithFormat:@"<html><head></head><body><h1>第%i章</h1><p>这里是利用UIPageViewController显示出来的第%i章的内容。</p></body></html>",i,i]; [pageStrings addObject:contentString]; } self.pageContent=[[NSArray alloc] initWithArray:pageStrings];}
在createContentPages这项措施中

1

NSMutableArray*pageStrings=[[NSMutableArrayalloc]init];

这行语句 创建了 一个数组物件pageStrings 用于存储 每个页面所需的html内容。

接下来的for()循环 会运行 十次,每运行 一次,都会创建 一个包含html内容的字符串 并且 将 这个字符串 添加到 数组物件pageStrings当中。

这项措施中最后

1self.pageContent=[[NSArray alloc] initWithArray:pageStrings];
这行语句 将 数组物件pageStrings的全部内容 存储 在createContentPages这项措施的实施对象所包含的数组物件pageContent当中。另外 我们 还需要 在pageAppViewController类型物件中的视图加载后 对这个类型的物件 采取 createContentPages这项措施,于是 我们 将pageAppViewController.m这个文件中的viewDidLoad这项措施 修改为 这样:

1

2

3

4

5

6

7

8

9

-(void)viewDidLoad

{

[superviewDidLoad];

[selfcreateContentPages];

}

现在 我们 为这个应用程序 设计好了 内容视图控制器 和 数据模型,接下来 我们 需要编写 为页面视图控制器提供数据的措施,也就是 UIPageViewControllerDataSource这项协议规定的两项措施,其中一项措施 用于生成 当前内容视图控制器之后的内容视图控制器,而另外一项措施 用于生成 当前内容视图控制器之前的内容视图控制器。

由于pageAppViewController这类物件 充当 页面视图控制器的数据源,所以 UIPageViewControllerDataSource这项协议规定的措施 必须适用于 pageAppViewController这类物件,于是 我们 要在pageAppViewController.m这个文件中 编写 这些措施。首先 我们 在pageAppViewController.m这个文件中 添加 这两项措施:

123456789101112131415161718192021222324252627-(NSUInteger)indexOfViewController:(ContentViewController *)contentViewController{ return [self.pageContent indexOfObject:contentViewController.dataObject];}-(ContentViewController *)viewControllerAtIndex:(NSUInteger)index{ if(([self.pageContent count]==0)||(index>=[self.pageContent count])) { return nil; } ContentViewController *contentViewController=[[ContentViewController alloc] initWithNibName:@"ContentViewController" bundle:nil]; contentViewController.dataObject=[self.pageContent objectAtIndex:index]; return contentViewController;}
其中 indexOfViewController这项措施 会收到 ContentViewController类型的视图控制器contentViewController 并且 找到 这个视图控制器 是 第几个视图控制器。这 是 这样办到的:先 把 视图控制器contentViewController中的数据物件dataObject提取出来,然后 对数组物件pageContent 采取 indexOfObject:这项措施 从而 找出 当前视图控制器所包含的数据物件dataObject 是 数组物件pageContent中的第几个,于是 就知道 当前的视图控制器 就是 第几个视图控制器了。viewControllerAtIndex:这项措施 会收到 NSUInteger类型的无标记整数 并且 存放 在变量index当中。然后 变量index的值 是 几,这项措施 就会生成 第几个内容视图控制器。在viewControllerAtIndex:这项措施中

1

2

3

4

5

6

7

if(([self.pageContentcount]==0)||(index>=[self.pageContentcount]))

{

returnnil;

}

这个if()语句 会判断 需要需要显示的页面数量 是否为 领 以及 变量index的值 是否超过了 需要显示的页面数量。如果 这两个条件 任意 满足 一个,则 将 nil 作为结果 传递回去,也就是 什么 都不传递回去。

接着

1ContentViewController *contentViewController=[[ContentViewController alloc] initWithNibName:@"ContentViewController" bundle:nil];
这行语句 利用 ContentViewController.xib这个文件中的设计 创建了 ContentViewController类型的内容视图控制器contentViewController。

1

contentViewController.dataObject=[self.pageContentobjectAtIndex:index];

这行语句 从数组物件pageContent 找出 当前页面需要显示的内容 并且 存储 在内容视图控制器contentViewController所包含的数据物件dataObject当中。

1return contentViewController;
这行语句 则将 已经准备好了的内容视图控制器contentViewController 作为结果 传递回去。刚刚编写的indexOfViewController: 和 viewControllerAtIndex:这两项措施 恰恰是 UIPageViewControllerDataSource这项协议所规定的措施中需要用到的。接下来 我们 编写 UIPageViewControllerDataSource这项协议所规定的两项措施。这两项措施 依然 写 在pageAppViewController.m这个文件中:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

-(UIViewController*)pageViewController:(UIPageViewController*)pageViewControllerviewControllerBeforeViewController:(UIViewController*)viewController

{

NSUIntegerindex=[selfindexOfViewController:(ContentViewController*)viewController];

if((index==0)||(index==NSNotFound))

{

returnnil;

}

index=index-1;

return[selfviewControllerAtIndex:index];

}

-(UIViewController*)pageViewController:(UIPageViewController*)pageViewControllerviewControllerAfterViewController:(UIViewController*)viewController

{

NSUIntegerindex=[selfindexOfViewController:(ContentViewController*)viewController];

if(index==NSNotFound)

{

returnnil;

}

index=index+1;

if(index==[self.pageContentcount])

{

returnnil;

}

return[selfviewControllerAtIndex:index];

}

其中 viewControllerBeforeViewController:viewController这项措施实施后,我们 可以得到 viewController这个内容视图控制器之前的内容视图控制器。而 viewControllerAfterViewController:viewController这项措施实施后,我们 可以得到 viewController这个内容视图控制器之后的内容控制器。

在viewControllerBeforeViewController:viewController这项措施中

1NSUInteger index=[self indexOfViewController:(ContentViewController *)viewController];
这行语句 检查 当前收到的内容视图控制器 是 第几个 并且 将 结果 存储 在变量index当中。

1

2

3

4

5

6

7

if((index==0)||(index==NSNotFound))

{

returnnil;

}

这个if()语句 检查 index的值 是否是 有效的值,如果 不是,则 什么 也不传递回去。

123index=index-1;return [self viewControllerAtIndex:index];
这两行语句 生成了 第index-1个内容视图控制器 并且 作为结果 传递回去。在viewControllerBeforeViewController:viewController这项措施当中

1

2

3

4

5

6

7

8

9

NSUIntegerindex=[selfindexOfViewController:(ContentViewController*)viewController];

if(index==NSNotFound)

{

returnnil;

}

这几行语句 先 检查 当前收到内容视图控制器 是 第几个内容视图控制器 并且 将 结果 存储 在变量index。接着 检查 当前 是不是收到了 内容视图控制器,如果 没有收到,也就是 变量index的值 为 常熟NSNotFound,则 什么 也不传递回去。

1234567891011index=index+1; if(index==[self.pageContent count]) { return nil; } return [self viewControllerAtIndex:index];
这几行语句 先 检查 index+1的值 是否超过了 所有内容视图控制器的数量,如果 没有超过,则创建 第index+1个内容视图控制器 并且 作为结果 传递回去。

创建 并且 初始化 页面视图控制器

整个应用程序的最后一步 就是 创建 一个页面视图控制器,也就是 UIPageViewController类型的物件 并且 正确地 对其 初始化。因为 应用程序 启动后,第一个呈现在用户面前的视图 就是 pageAppViewController类型视图控制器所包含的视图,而 pageAppViewController类型视图控制器中的视图 一加载完毕,适用于这类视图控制器的措施viewDidLoad: 就会得以实施,所以 我们 在viewDidLoad:这项措施中 创建 并且 初始化 页面视图控制器。我们 需要将 viewDidLoad:这项措施 在原来的基础之上 修改为 这样:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

-(void)viewDidLoad

{

[superviewDidLoad];

[selfcreateContentPages];

NSDictionary*options=[NSDictionarydictionaryWithObject:[NSNumbernumberWithInteger:UIPageViewControllerSpineLocationMin]forKey:UIPageViewControllerOptionSpineLocationKey];

self.pageViewController=[[UIPageViewControlleralloc]initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurlnavigationOrientation:UIPageViewControllerNavigationOrientationHorizontaloptions:options];

self.pageViewController.dataSource=self;

[pageViewController.viewsetFrame:[self.viewbounds]];

ContentViewController*initialViewController=[selfviewControllerAtIndex:0];

NSArray*viewControllers=[NSArrayarrayWithObject:initialViewController];

[self.pageViewControllersetViewControllers:viewControllersdirection:UIPageViewControllerNavigationDirectionForwardanimated:NOcompletion:nil];

[selfaddChildViewController:self.pageViewController];

[self.viewaddSubview:self.pageViewController.view];

[pageViewControllerdidMoveToParentViewController:self];

}

在编译 并且 运行 这个程序之前,我们 需要花一点 时间 来分析一下 viewDidLoad:这项措施中的代码。

1NSDictionary *options=[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin] forKey:UIPageViewControllerOptionSpineLocationKey];
这行语句 创建了 一个NSDictionary类型的物件options 用来存储 UIPageViewControllerOptionSpineLocationKey这个选项。UIPageViewControllerOptionSpineLocationKey这个选项 代表了 页面视图控制器中 “书脊”的位置。我们 这里 将 UIPageViewControllerOptionSpineLocationKey的值 设定为了 UIPageViewControllerSpineLocationMin,这 表明 我们 将 “书脊”的位置 设定 在页面视图控制器的最左边。

1

self.pageViewController=[[UIPageViewControlleralloc]initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurlnavigationOrientation:UIPageViewControllerNavigationOrientationHorizontaloptions:options];

这行语句 为页面视图控制器 分配了 内存地址 并且 对其 采取了 initWithTransitionStyle:navigationOrientation:options这项措施。其中 第一个参数UIPageViewControllerTransitionStylePageCurl 表明 两个视图之间切换的效果 为 “翻页”的效果;第二个参数UIPageViewControllerNavigationOrientationHorizontal 表明 翻页的方向 为 左右翻页,而不是
上下翻页;第三个参数options中 则存储了 页面视图控制器的“书脊”位置。

1self.pageViewController.dataSource=self;
这行语句 将 页面视图控制器pageViewController的数据源 设定为了 pageAppViewController类型的视图控制器。

1

[pageViewController.viewsetFrame:[self.viewbounds]];

这行语句 先获取了 pageAppViewController类型视图控制器所包含的视图,然后 对其 采取了 bounds这项措施 从而 获得 这个视图的大小 和 位置。最后 将 页面视图控制器pageViewController中的视图view的大小 和 位置 设定为 刚刚获得的数值。

在页面视图控制器 显示出来之前,我们 必须手工创建 第一个内容视图控制器,而

1ContentViewController *initialViewController=[self viewControllerAtIndex:0];
这行语句 就创建了 第一个内容视图控制器initialViewController。

1

NSArray*viewControllers=[NSArrayarrayWithObject:initialViewController];

这行语句 将 第一个内容视图控制器initialViewController 装入 数组物件viewControllers当中。接着 包含着第一个内容视图控制器的数组物件 需要装入 页面视图控制器pageViewController:

1[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
第一个参数UIPageViewControllerNavigationDirectionForward 将 导航方向 设定为了 正向。

1

[selfaddChildViewController:self.pageViewController];

这行语句 将 pageAppViewController类型的视图控制器的子视图控制器 设定为 页面视图控制器pageViewController。

1

[self.viewaddSubview:self.pageViewController.view];

这行语句 将 页面视图控制器pageViewController所包含的视图view 作为子视图 添加到 pageAppViewController类型视图控制器所包含的视图上。

将 子视图控制器 添加到 主视图控制器中后,我们 需要对子视图控制器 采取 didMoveToParentViewController:这项措施 并且 将 主视图控制器 作为参数。


编译 并且 运行 这个程序

编译 并且 运行 这个程序后,我们 可以看到 这样的效果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: