原文:http://www.techotopia.com/index.php/An_Example_iOS_5_iPhone_UIPageViewController_Applicationphp
在Xcode中新建項目時,能夠選擇「Page-based Application」項目模板。能夠利用這個模板建立一種「基於頁」的應用程序,在1年的每月中顯示不一樣的頁。奇怪的是,這是Xcode提供的惟一一個基於實例的模板而不是應用程序基本框架。這對於一開始學習時頗有用,但除非你真的須要一個用12頁來顯示1年不一樣月份的程序,不然你必需從這個模板中移除一些已有的東西,以用於其餘目的。html
實際上,除了使用Xcode’s的「Page-based Application」模板,咱們也可使用Single View Application 模板,只不過本身須要實現Page-based的行爲。這有兩方面的好處。首先,不使用Page-base模板能使咱們更能理解UIPageViewController的實現細節。其次,這種方式也比去修改Page-based Application模板要更加簡捷。web
啓動Xcode,新建iOS single view application項目,確認不要使用Use Storyboard選項。數組
本示例使用單個View Controller實例顯示多個頁。視圖中包含了一個UIWebView,根據當前選擇的頁顯示不一樣Html內容。ViewController類有一個data對象屬性用於持有視圖的Html。app
選擇FileàNewàNewFile…菜單,新建UIViewController subclass,名爲contentViewController(勾選「With XIB…」選項)。打開contentViewController.h,爲webview對象和data對象添加出口並進行鏈接。框架
#import <UIKit/UIKit.h>
@interface contentViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIWebView *webView;
@property (strong, nonatomic) id dataObject;
@end
而後,打開contentViewController.xib,拖一個UIWebView組件到view上:學習
右鍵從File’s Owner 拖一條鏈接線到web view對象並選擇webView出口。ui
編輯contentViewController.m文件。每當用戶翻頁時,UIPageViewController的數據源方法會建立一個新的contentViewController實例而後設置其dataObject屬性爲相應的Html。而在contentViewController的viewWillAppear方法中,咱們會將dataObject屬性賦給webview對象。爲此,咱們加入了必要的@synthesize語句,同時修改了viewWillAppear方法:atom
#import "contentViewController.h"
@implementation contentViewController
@synthesize webView, dataObject;
.
.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[webView loadHTMLString:dataObject
baseURL:[NSURL URLWithString:@""]];
}
.
.
@end
接下來,咱們來實現數據模型。url
本例中的數據模型是一個字符串數組。每一個字符串是內容不一樣的Html內容。pageAppViewController類就是UIPageViewController對象的數據源。該類含有一個NSArry和一個UIPageViewController對象,同時實現UIPageViewcontrollerDataSource協議。打開pageAppViewController.h,導入contentViewController.h頭文件,加入必要的聲明:
#import <UIKit/UIKit.h>
#import 「contentViewController.h」
@interface pageAppViewController : UIViewController <UIPageViewControllerDataSource> {
UIPageViewController *pageController;
NSArray *pageContent;
}
@property (strong, nonatomic) UIPageViewController *pageController;
@property (strong, nonatomic) NSArray *pageContent;
@end
最後,在pageAppViewController.m中增長一個方法以把Html字符串加到數組中。而後在viewDidLoad方法中調用這個方法。
#import "pageAppViewController.h"
@implementation pageAppViewController
@synthesize pageController, pageContent;
.
.
- (void) createContentPages {
NSMutableArray *pageStrings = [[NSMutableArray alloc] init];
for (int i = 1; i < 11; i++)
{
NSString *contentString = [[NSString alloc]
initWithFormat:@"<html><head></head><body><h1>Chapter %d</h1><p>This is the page %d of content displayed using UIPageViewController in iOS 5.</p></body></html>", i, i];
[pageStrings addObject:contentString];
}
pageContent = [[NSArray alloc] initWithArray:pageStrings];
}
.
.
- (void)viewDidLoad {
[super viewDidLoad];
[self createContentPages];
}
如今,咱們已經有一個content view controller和一個data model了,data model將經過數據源方法來提取每一頁的內容。下一步,就是實現這些數據源方法。如「Implementinga Page based iOS 5 iPhone Application using UIPageViewController」中所述, UIPageViewController 實例須要一個數據源,數據源方法有兩個,一個是返回當前顯示的view controller以後的view controller,而另外一個是返回當前顯示的view controller以前的viewcontroller。因爲pageAppViewController扮演了page view controller的數據源,所以須要在pageAppViewController.m中加入這兩個方法(以及另外兩個便利方法)。首先咱們來看這2個便利方法:
#import "pageAppViewController.h"
@implementation pageAppViewController
@synthesize pageController, pageContent;
- (contentViewController *)viewControllerAtIndex:(NSUInteger)index {
// Return the data view controller for the given index.
if (([self.pageContent count] == 0) ||
(index >= [self.pageContent count])) {
return nil;
}
// Create a new view controller and pass suitable data.
contentViewController *dataViewController =
[[contentViewController alloc]
initWithNibName:@"contentViewController"
bundle:nil];
dataViewController.dataObject =
[self.pageContent objectAtIndex:index];
return dataViewController;
}
- (NSUInteger)indexOfViewController:(contentViewController *)viewController {
return [self.pageContent
indexOfObject:viewController.dataObject];
}
.
.
@end
viewControllerAtIndex: 方法首先檢查有效頁數是否<0(用戶不可能回到第1頁之前)或者要檢索的頁數已經超出了pageContent數組的實際數目。若是index參數有效,就建立一個新的contentViewController實例並將dataObject屬性設置爲相應的pageContent條目(Html字串)。
indexOfViewController 方法指定一個viewController做爲參數,並返回這個viewController的索引。它使用viewcontroller的dataObject屬性去在pageContent數組元素中檢索其索引
如今來看兩個數據源方法。它們使用這兩個便利方法返回當前view controller「以前」和「以後」的view controller:
- (UIViewController *)pageViewController: (UIPageViewController *)pageViewController viewControllerBeforeViewController: (UIViewController *)viewController {
NSUInteger index = [self indexOfViewController:
(contentViewController *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController: (UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [self indexOfViewController:
(contentViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageContent count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
下一步,就是建立和實例化UIPageViewController類。
接下來就是建立UIPageViewController實例並初始化。用於這個過程只須要進行一次,所以把代碼寫在pageAppViewController的viewDidLoad方法中就能夠了。打開pageAppViewController.m 文件修改 viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
[self createContentPages];
NSDictionary *options =
[NSDictionary dictionaryWithObject:
[NSNumber
numberWithInteger:UIPageViewControllerSpineLocationMin]
forKey: UIPageViewControllerOptionSpineLocationKey];
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options: options];
pageController.dataSource = self;
[[pageController view] setFrame:[[self view] bounds]];
contentViewController *initialViewController =
[self viewControllerAtIndex:0];
NSArray *viewControllers =
[NSArray arrayWithObject:initialViewController];
[pageController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
[self addChildViewController:pageController];
[[self view] addSubview:[pageController view]];
[pageController didMoveToParentViewController:self];
}
所有代碼到此結束。在編譯和運行程序以前,咱們先分析一下viewDidLoad方法中的代碼。
構建數據模型以後,咱們建立了一個NSDictionary對象。這個NSDictionary中包含了一個options,用於page controrller對象的初始化選項。在這裏,該選項指定了spine位於屏幕左側(spine即書脊,書頁裝訂的位置,書從另外一側翻閱):
NSDictionary *options = [NSDictionary dictionaryWithObject: [NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin] forKey: UIPageViewControllerOptionSpineLocationKey];
下一句,用前面的options實例化UIPageViewController:
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options: options];
要讓類成爲page controller的數據源,還要作一些配置。好比咱們要讓頁面全屏,須要設置它的frame:
pageController.dataSource = self;
[[pageController view] setFrame:[[self view] bounds]];
在第1頁能顯示以前,咱們首先須要建立一個view controller。這能夠調用 viewControllerAtIndex: 便利方法。 在得到一個contentview controller後,把它放到一個數組對象中:
contentViewController *initialViewController =
[self viewControllerAtIndex:0];
NSArray *viewControllers =
[NSArray arrayWithObject:initialViewController];
注意,只須要一個content view controller。由於page controller被設定爲一次只顯示1頁(單面)。若是將pagecontroller配置爲2頁(spine位於中央)或者雙面,則須要建立2個content view controller並放入數組。
而後,將數組對象賦給view controller並將導航方向設置爲向前模式:
[pageController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
最後,將page vview controller加到當前視圖:
[self addChildViewController:pageController];
[[self view] addSubview:[pageController view]];
[pageController didMoveToParentViewController:self];
點擊Run,運行程序。第1頁將顯示出來。從右到左滑動屏幕,將翻到下一頁,作相反方向滑動則翻到上一頁。