原文:http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/
在上一篇文章(http://blog.csdn.net/u011156012/article/details/37592445)中介绍了利用scrollview实现引导页,那种方法虽然简单,但是有一个缺点就是没法实现引导页页数的现实,就如下面图中所思的4个小灰点。曾经想过在引导页显示的图片上ps上不同的点表示页数,但是这样做的bug是当用户划屏时,其实那个点也被划走了。所以,研究下利用ios自带的pageviewcontroller来实现引导页。
下面是原文,因为整片文章还是比较容易理解的,所以只把重点的地方翻译出来,然后最后贴上完整的代码。
the demo app we are going to create is very simple. it displays 4 pages of screens to give users a brief introduction to the user interface. user can navigate between pages by swiping through the screen. whenever user taps the “start again” button to go back
to the first page of tutorial. this type of walkthrough/tutorial screens shouldn’t be new to you as they are commonly found in apps such as snapguide and airbnb.
我的代码里面没有把start again功能加进去,因为个人感觉引导页是能够左右滑动的,所以稍微改动了下,而不是只能向后划屏。
launch xcode and create a new project by using the single view application template. it might seem a little bit strange to select the single view application template as xcode already comes with a page-based application template, which contains a fully functional
app based on the uipageviewcontroller. however, this template is a little bit complex and it will take us more time to clean-up the code of the template than to start from scratch. needless to say, we can better grasp the concept behind the uipageviewcontroller
when we start from scratch.

okay, let’s move on. in the next screen enter pageviewdemo as the product name and set com.appcoda in the company identifier field. select iphone for the devices option. press next and create the project.
建立程序没啥好说的,很简单。
next, select the main.storyboard. as usual, you should find a default view controller generated by xcode. leave it as it is. drag a page view controller from the object library into the storyboard. then add another view controller and put it in the same storyboard.
for this project, the original view controller(最左面的view controller)
is used as the root view controller for holding the page view controller. the view controller you’ve just added(右下角的view controller) will be used for displaying
the page content. throughout the article, we refer the original view controller as the root view controller and the other view controller as
page content controller.
说白了就是原始的view controller是用来显示pageviewcontroller的视图,而后添加的view controller是用来承载pageviewcontroller的内容的。这在后面会有进一步的介绍。
you may wonder why we just add a single view controller for 4 pages of content. shouldn’t we use four view controllers instead of one? as you can see from the final deliverable, the walkthrough screens are very similar. it’s better to share the same view controller
for different screens.
因为4个引导页长的非常类似,基本上引导页的布局都是一样的,很少有不同风格的引导页布局,所以,我们仅仅用1个view controller来承载,这样也由利于节省内存。
next, assign a storyboard id for the page view controller and the page content controller. you can simply select the controller and set the id under identity inspector. set the storyboard id of the page view controller as “pageviewcontroller” and name the id
of the page content controller as “pagecontentcontroller”. later we’ll refer to these ids in our code.
和我在上篇博文中提到的,要在ib中把view controller的storyboard id指定一下,因为我们在手动写代码时需要生成view controller的实例。这里我们把page view controller的storyboard名字命名为pageviewcontroller, 而把后建立的用户承载内容的view controller的storyboard id命名为 pagecontentcontroller
by default, the transition style of the page view controller is set as page curl. the page curl style is perfect for book apps. for walkthrough screens, we prefer to use scrolling style. so change the transition style to scroll under attribute inspector.
把transition style修改为scroll,这样就是用户习惯的滑动了;刚试了一下,默认的page curl是类似与翻书页的方式,而且如果你选择了page curl方式,就会默认把图片下方的4个小点点去掉了。如果你愿意,还可以修改划屏的方向,navigation默认的是水平的。
we’ll design the user interface of page content view controller. drag an image view and a label into the controller. you’re free to change the font type and size. but your view controller should be similar to the below screenshot.
在page content view controller页面添加进来image view和label,这基本上也就是我们的引导页需要的大部分内容了吧。
for the default view controller, add a “start again” button and put it at the below of the screen.
注意我的代码里面没有添加进这个功能,因为这个功能没什么难点,很简单的按钮功能。
the next step is to create view controller class and associate it with the corresponding view controller. from the menu, select file -> new -> file … and choose the “objective-c class” template. name the class as pagecontentviewcontroller and make it a subclass
of uiviewcontroller.
为我们新添加的view controller(注意不是pageviewcontroller)添加类,很简单,新建一个objective-c的类,然后把类名修改为pagecontentviewcontroller
go back to storyboard. select the page content view controller and set the custom class to pagecontentviewcontroller under identify inspector.
返回到ib中,把右下角的view controller的custom class修改为我们新添加的类。
next, we’ll create outlets for the image view and label. switch to the assistant editor and make sure the pagecontentviewcontroller.h is opened. control and drag from the image view to the pagecontentviewcontroller.h and create an iboutlet. set the name as
backgroundimageview for the image view. for the label, set the name of the outlet as titlelabel.
after the change, the pagecontentviewcontroller.h should look like this:
然后打开助手模式,然后修改.h文件成如下的样子,怎样修改我就不多说了,按着control然后拖拽就好了。
1
2
3
4
5
6
7
#import <uikit/uikit.h>
@interface pagecontentviewcontroller : uiviewcontroller
@property (weak, nonatomic) iboutlet uiimageview *backgroundimageview;
@property (weak, nonatomic) iboutlet uilabel *titlelabel;
@end
next, select the root view controller and make sure the viewcontroller.h is opened. create an action for the “start again” button and name the action as “startwalkthrough”.
给start again 按钮添加操作,注意我的实例代码中没有这个。
okay, we’ve completed the design of user interface and created all the outlets. let’s move onto the implementation of the view controller classes.
it’s very straightforward to implement the page content view controller. first, add the following properties in
pagecontentviewcontroller.h:
打开.h文件,添加3个property。
@property nsuinteger pageindex;
@property nsstring *titletext;
@property nsstring *imagefile;
the pageindex stores the current page index (or page number). the view controller is designed to display an image and a title. so we create two parameters for passing the title text and image file. next, open pagecontentviewcontroller.m and change the viewdidload:
method:
pageindex是当前页面的页码,剩下的两个nsstring都可以从字面上理解它们的含义和作用了。接下来修改.m文件的viwedidloat函数成如下形式:
- (void)viewdidload
{
[super viewdidload];
self.backgroundimageview.image = [uiimage imagenamed:self.imagefile];
self.titlelabel.text = self.titletext;
}
接下来介绍了pageviewcontroller的相关属性。
the uipageviewcontroller class is classified as a container controller. the container controller is used to contain and manage multiple view controllers shown in the app, as well as, controlling the way one view controller switches to another. here the uipageviewcontroller
is the container controller that lets the user navigate from page to page, where each page is managed by its own view controller object. the following illustration depicts the relationship between the page view controller and the page content view controller.
其实pageviewcontroller就是一个容器,他里面有很多不同的page content view controller,pageviewcontroller用来控制这些不同page content的切换方式等等。因为我们的引导页都是同样的布局,所以我们仅用1个pagecontent viewcontroller(ib中右下角的view controller)来完成。
in order to make uipageviewcontroller work, we must adopt the uipageviewcontrollerdatasource protocol. the data source for a page view controller is responsible for providing the content view controllers on demand. by implementing the data source protocol,
we tell the page view controller what to display for each page.
我们同时还要指定pageviewcontrollerdatasource的代理,这样才能通过修改代理的方法告诉pageviewcontroller展示那些页面以及展示的方法等。
in this case, we use the viewcontroller class as the data source for the uipageviewcontroller instance. therefore it is necessary to declare the viewcontroller class as implementing the uipageviewcontrollerdatasource protocol.
the viewcontroller class is also responsible to provide the data of the page content (i.e. images and titles). open the viewcontroller.h. modify the @interface declaration, add a new property to hold the uipageviewcontroller, as well as, properties for both
images and titles:
因为我们用viewcontroller来提供数据,包括标题和图片,所以我们打开viewcontroller.h文件添加uipageviewcontrollerdatasource代理
8
9
10
11
#import "pagecontentviewcontroller.h"
@interface viewcontroller : uiviewcontroller <uipageviewcontrollerdatasource>
- (ibaction)startwalkthrough:(id)sender;
@property (strong, nonatomic) uipageviewcontroller *pageviewcontroller;
@property (strong, nonatomic) nsarray *pagetitles;
@property (strong, nonatomic) nsarray *pageimages;
in the viewcontroller.m, initialize the pagetitles and pageimages in the viewdidload method:
在viewcontroller.m文件中,先初始化标题和图片的数据。我们可以自己手动拖4个图片进来,也可以去下面提供的链接里面下载图片。
_pagetitles = @[@"over
200 tips and tricks", @"discover hidden features", @"bookmark
favorite tip", @"free regular update"];
_pageimages = @[@"page1.png", @"page2.png", @"page3.png", @"page4.png"];
note: you can download image files from here and add them into the xcode project.
we have created the data model for the page content. next, we have to implement at least two methods of the uipageviewcontrollerdatasource protocol:
viewcontrollerafterviewcontroller – provides the view controller after the current view controller. in other words, we tell the app what to display for the next screen.
viewcontrollerbeforeviewcontroller – provides the view controller before the current view controller. in other words, we tell the app what to display when user switches back to the previous screen.
接下来需要修改我们的代理中的5个最重要的函数了,先说其中的2个 viewcontrollerafterviewcontroller和viewcontrollerbeforeviewcontroller,从字面上不难理解,这两个函数告诉pageviewcontroller用户向左向右(向上向下)划屏之后需要显示的页面。在这两个函数中,我们需要返回的是uiviewcontroller的一个指针,所以我们看到返回的是 viewcontrolleratinder:index,所以,我们需要实现一个这个函数。
add the following lines of code before the end of the viewcontroller.m file:
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#pragma mark - page view controller data source
- (uiviewcontroller *)pageviewcontroller:(uipageviewcontroller *)pageviewcontroller
viewcontrollerbeforeviewcontroller:(uiviewcontroller *)viewcontroller
nsuinteger index = ((pagecontentviewcontroller*) viewcontroller).pageindex;
if ((index == 0) || (index == nsnotfound)) {
return nil;
}
index--;
return [self viewcontrolleratindex:index];
viewcontrollerafterviewcontroller:(uiviewcontroller *)viewcontroller
if (index == nsnotfound) {
index++;
if (index == [self.pagetitles
count]) {
the above methods are very straightforward. first, we get the current page index. depending the method, we simply increase/decrease the index number and return the view controller to display. of course, we have to verify if we have reached the boundaries of
the pages and return nil in that case.
as you may notice, we haven’t created the viewcontrolleratindex: method. it is a helper method that is designed to create the page content view controller on demand. it takes in the index parameter and creates the corresponding page content controller.
in the viewcontroller.m, add the helper method:
viewcontrolleratindex函数,这里面我们需要生成一个pagecontentviewcontroller(右下角viewcontroller)的实例,需要用到之前在ib中添加的stroyboard 的id了。
- (pagecontentviewcontroller *)viewcontrolleratindex:(nsuinteger)index
if (([self.pagetitles
count] == 0) || (index
>= [self.pagetitles count])) {
// create a new view controller and pass suitable data.
pagecontentviewcontroller *pagecontentviewcontroller = [self.storyboard instantiateviewcontrollerwithidentifier:@"pagecontentviewcontroller"];
pagecontentviewcontroller.imagefile = self.pageimages[index];
pagecontentviewcontroller.titletext = self.pagetitles[index];
pagecontentviewcontroller.pageindex = index;
return pagecontentviewcontroller;
recalled that we have set a storyboard id for the view controllers when designing the user interface. the id is used as reference for creating the view controller instance. to instantiate a view controller in storyboard, you can use the instantiateviewcontrollerwithidentifier:
method with a specific storyboard id.
pagecontentviewcontroller *pagecontentviewcontroller = [self.storyboard instantiateviewcontrollerwithidentifier:@"pagecontentviewcontroller"];
to display a page indicator, you have to tell ios the number of pages (i.e. dots) to display in the page view controller and which page must be selected at the beginning. add the following two methods at the end of the viewcontroller.m file:
接下来还需要另外2个pageviewcontrollerdatasource的代理中的函数来告诉ios
pageview的页数以及首次展示的图片是哪一张。
- (nsinteger)presentationcountforpageviewcontroller:(uipageviewcontroller *)pageviewcontroller
return [self.pagetitles count];
- (nsinteger)presentationindexforpageviewcontroller:(uipageviewcontroller *)pageviewcontroller
return 0;
again the above code is very straightforward. we simply tell ios that we have the total number of pages to display in the page view controller and the first page should be selected by default.
note: you must implement both methods in order to display the page indicator. also the page indicator only works in scroll transition mode.
the final step is to create and initialize the uipageviewcontroller. the best place to do that is in the viewdidload method. open the viewcontroller.m file and change the method to:
最后一步就是初始化pageviewcontroller了,初始化的最佳地点当然就是viewdidload了,修改viewcontroller.m 的相关函数如下:
// create the data model
// create page view controller
self.pageviewcontroller = [self.storyboard instantiateviewcontrollerwithidentifier:@"pageviewcontroller"];
self.pageviewcontroller.datasource = self;
pagecontentviewcontroller *startingviewcontroller = [self viewcontrolleratindex:0];
nsarray *viewcontrollers = @[startingviewcontroller];
[self.pageviewcontroller setviewcontrollers:viewcontrollers direction:uipageviewcontrollernavigationdirectionforward
animated:no completion:nil];
// change the size of page view controller
self.pageviewcontroller.view.frame = cgrectmake(0, 0,
self.view.frame.size.width, self.view.frame.size.height - 30);
[self addchildviewcontroller:_pageviewcontroller];
[self.view addsubview:_pageviewcontroller.view];
[self.pageviewcontroller didmovetoparentviewcontroller:self];
let’s see what the method does. we first create the pageviewcontroller instance. next we specify the data source, in this case it is the class itself. we then create the first page content controller, add it to an array of controllers and assign it to the page
view controller for display.
我们先创建一个pageviewcontroller的实例,当然方法和前面的方法一样,利用早前我们在ib中定义的storyboard id。然后赋予它 data source
lastly, we change the size of the page view controller and add the page controller view to the current view.
到这里我们引导页程序就完成了,但是运行后我们会发现没有图片下方的4个点点表示页数,在添加下面的内容就大功告成了!
if you compile and run the app now, your app should run properly but you may find the page indicator missing. actually the page indicator is there but the color of the dots is the same as the color of the view. so let’s change its color.
in the appdelegate.m, add the following lines of code in the didfinishlaunchingwithoptions: method:
uipagecontrol *pagecontrol = [uipagecontrol appearance];
pagecontrol.pageindicatortintcolor = [uicolor lightgraycolor];
pagecontrol.currentpageindicatortintcolor = [uicolor blackcolor];
pagecontrol.backgroundcolor = [uicolor whitecolor];
and there we go, start the application and see how the uipageviewcontroller works. you should be able to load the page view controller by using the iphone simulator. try to swipe through the screen to navigate between pages.
there is still one thing left. the “start again” is not yet implemented. when tapped, we expect the page view controller will scroll back to the first page. you can use the setviewcontrollers: method of the uipageviewcontroller to switch page. to go back to
the first page of the page view controller, change the startwalkthrough: method of viewcontroller.m:
这是我没有添加进来的按钮功能,很简单。
- (ibaction)startwalkthrough:(id)sender {
[self.pageviewcontroller setviewcontrollers:viewcontrollers direction:uipageviewcontrollernavigationdirectionreverse
run the app again. the app will bring you back to the first page when tapping the “start again” button.
好了下面贴上完整的代码:
appdelegate.m:
viewcontroller.h
viewcontroller.m
pageviewcontentviewcontroller.h 注意我这里写的时pageviewcontentviewcontroller其实就是pagecontentviewcontroller
pageviewcontentviewcontroller.m