使用UIPageViewController进行多页面管理
Do it step by step!
在制作app的引导页的时候会用到UIPageViewController,有多个水平关系的ViewController也能够用UIPageViewController来管理。这个例子使用的数据来自豆瓣的开放API,会使用Alamofire去请求数据,并用SDWebImage加载图片,因此你的电脑上需要安装有Cocoapods,方便第三方库的引入。
前期准备
1.新建一个项目,选择Single View Application
2.Product Name填PageViewControllerDemo,语言选择Swift
3.右键点击ViewController.swift代码文件,将它删掉,在弹出的提示框中选择Move To Trash
4.使用Command + N快捷键新建一个文件,选择Cocoa Touch Class
5.创建一个UIViewController的子类,将它命名为MainController。在接下来的部分,将会看到MainController的作用是用来给UIPageViewController提供相应的ViewController,并对页面改变做出响应。
6.打开Main.storyboard,现在只有一个Scene在Main.storyboard中,选中这个scene让它和MainController.swift代码文件关联
暂时把项目关掉,引入第三方库之后,再重新打开。
接下来我们开始使用Cocoapods引入Alamofire和SDWebimage
7.使用终端进入项目所在的目录,使用cd <项目路径>命令,回车之后就进入了项目所在目录
8.在终端敲入这条命令touch Podfile,回车,这样就创建了Podfile文件
9.打开项目文件夹,你会发现多了一个Podfile文件,双击打开Podfile,将下面这段安装命令复制到Podfile中
platform :ios, '8.0'
use_frameworks!
pod 'Alamofire'
pod 'SDWebImage'
10.关闭Podfile,回到终端,在终端里面敲入pod install命令,回车,安装第三方库。
等待....安装完成之后,会有和截图类似结果。
请注意终端里的最后一句绿色的文字,它说从现在开始要使用PageViewControlerDemo.xcworkspace来打开项目了,因此以后打开这个项目时不能再使用双击PageViewControlerDemo.xcodeproj的方式。
布局阶段
1.打开项目,并打开storyboard,选中MainController,将它嵌入到NavigationController中。
2.从控件库中拖3个Button到MainController,把它们平铺在navigationBar的下方,这些Button用来切换不同的页面。
3.同时选中这3个Button,改变它们的一些属性
属性 | 相应的值 |
---|---|
宽度 高度 | 200,40 |
背景颜色 | RGB(248, 248, 248) |
字体颜色 | 黑色 |
完成之后,如下所示
4.接下来为button添加约束,以下是我们需要实现的约束
- button位于navigationBar的正下方
- 每个button的宽度为屏幕宽度的1/3
- 每个button等高等宽
- 彼此相邻
选中最左边的button,点击设计面板右下方的第三个按钮,给它添加左边,上边,以及高度这三个约束
按住control键,用鼠标左键从button中往空白处拖,可以看到一条蓝色的线,松开鼠标左键,在弹出菜单中选择Equal Widths
我们要button的宽度为屏幕的1/3,而不是完全等于屏幕宽度,因此要修改一个系数,在Document outline中选中Botton.width约束,将Multiplier改为1/3
接下来为剩下的两个button添加约束,选中第二个button,按住control键,用鼠标左键向第一个button拖,放开左键,按住shift键,在弹出菜单中选择Horizontal Spacing,Top,Equal Widths,Equal Heights,最后点击Add Constraints
最后一个button也用同样的方法给它加上约束
最后在不同的模拟器运行一遍看看有什么效果,或者用预览的方式看也行。可以看到button是均匀排列的
5.添加当前页面提示条,在button的下方会有一个红色的条,用来提醒当前是哪个页面,顺便把的button的Title分别改为(电影,音乐,图书),因为使用了豆瓣的API获取了这三种不同的数据。
首先从控件库里面拉一个View到button的下方,为了看的清楚一点,给View的设置一个深一点的背景色,选中它,添加以下4个约束,在Update Frames选择Items of New Constraints,最后点添加
6.在MainController中嵌入一个UIPageViewController,让UIPageViewController成为MainController的SubViewController,执行以下的5个操作
- 从控件库中找到Container View,并把它拖到MainController的空白处
- 会发现多了一个ViewController,把它删掉
- 选中Container View,给它添加上下左右都为0的4个约束
- 从控件库中找到Page View Controller,并把它拖到设计面板的空白处
- 选中Container View,按住control键,用鼠标左键向第一个Page View Controller拖,放开左键,从弹出菜单中选择Embed
经过上面的5个步骤,就把Page View Controller嵌入到MainController中了,这个过程也可以用代码来实现的。下面是完成之后的截图
7.接下开是3个真正要展示内容的页面,因为3个页面的布局一摸一样,因此只把第一个页面的步骤记下来,剩下的两个是相同的。
在控件库中拖一个View Controller到设计面板的空白处,选中这个刚添加的View Controller,把它的Storyboard ID设置为MovieControllerID
在这个View Controller中添加一个TableView,改变TableView的大小,让它铺满整个View Controller,然后点击设计面板右下方的最后一个布局按钮,在弹出菜单中选择Add Missing Constraints
这时新建一个代码文件和这个View Controller关联起来。Command + N,选择Cocoa Touch Class,创建一个UIViewController的子类,把它命名为MovieController,最后回到storyboard把View Controller和MovieController关联起来,这样就可以在MovieController.swift代码文件中添加代码来控制相应的View Controller
8.执行第7步的内容,创建接下来的两个页面,对应如下
StoryBoard ID | 代码文件名 | 关联的View Controller |
---|---|---|
MovieControllerID | MovieController.swift | Movie Controller |
MusicControllerID | MusicController.swift | Music Controller |
BookControllerID | BookController.swift | Book Controller |
完成后代码文件的结构,以下是完成上面步骤后的代码文件结构图,和storyboard截图
还差一点点,布局工作就要完成了,加油!!!!
9.创建一个通用的UITableViewCell的子类,用来显示图片的标题。创建一个新的文件,同样选择Cocoa Touch Class,不过这次要继承UITableViewCell,把它命名为CommonCell,同时勾选Also create XIB file
10.打开CommonCell.xib,将Common Cell的高度设置为150
11.为Common Cell添加Image View和Label。执行以下步骤
- 拖放一个Image View到Common Cell中,将它的宽高分别设置为120,150
- 给Image View添加如下约束
- 拖放一个Label到Common Cell中
- 给Label添加如下约束,并把它的文字设置为居中
完成之后
12.选中Common Cell,打开辅助视图,为Image View和Label生成相应的outlet。Image View对应的outlet为coverImageView,Label对应的outlet为titleLabel
13.回到storyboard分别为Movie Controller,Music Controller,BookController的tableView生成相应的outlet。
View Controller | Table View Outlet |
---|---|
Movie Controller | movieTableView |
Music Controller | musicTableView |
Book Controller | bookTableView |
14.选中MainController的button,从左到右依次把它们的tag设置为100,101,102
到这里为止所有的布局就结束了,接下来就是代码部分了!
代码环节
在写代码之前,先创建几个分组,方便代码的分类和管理。右键点击PageViewControllerDemo分组,选择New Group,输入新的分组名Controller。用同样的方式创建以下5个分组,View,DataModel,Other,Storyboard & XIB,Helper。
分组是组织代码的一种方式,把具有相似功能的代码放到一个分组中。完成后,代码文件结构会和下面的截图类似
现在开始写代码
1.右键Helper分组,新建一个SWift File,把它命名为GetDataFromDouBan
import Alamofire //导入Alamofire, 以便执行网络请求
class GetDataFromDouBan {
/**
用来从豆瓣开放平台中获取数据的帮助方法
- parameter dataURL: 请求URL(对应电影,音乐,图书的请求地址)
- parameter type: 类型分别是subjects,musics,books
- parameter keyword: 搜索关键字
- parameter completedHandle: 数据接收到之后的处理函数
*/
static func getData(dataURL: String, type: String, keyword: String, completedHandle: (data: [NSDictionary]) -> Void) {
//请求数据
Alamofire.request(.GET, dataURL, parameters: ["q": keyword, "count": "10"], encoding: ParameterEncoding.URL, headers: nil).responseJSON { (response: Response<AnyObject, NSError>) -> Void in
//获取返回的内容
if let result = response.result.value {
//拿到电影,音乐,图书的信息
if let data = result[type] as? [NSDictionary] {
//回到主线程,执行UI更新等操作
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
completedHandle(data: data)
})
}
}
}
}
}
上面的代码看不懂也没有关系,它的作用是用来获取电影,音乐,图书等数据的,拿到数据之后,就会执行completedHandle(data: data)函数,进行数据模型的搭建,UI的刷新等
2.回到MainController.swift代码文件,这是我们的主控制器。首先添加一个属性,通过这个属性来引用我们嵌入到Main Controller的UIPageViewController
var pageViewController: UIPageViewController!
在viewDidLoad()方法中,添加下面这句代码。它获取MainController的所有子视图控制器,因为只有一个,所以第一个就是UIPageViewController
//获取到嵌入的UIPageViewController
pageViewController = self.childViewControllers.first as! UIPageViewController
在pageViewController属性的下面添加3个变量,以此来引用在前面创建的3个页面
var pageViewController: UIPageViewController!
var movieController: MovieController!
var musicController: MusicController!
var bookController: BookController!
在viewDidLoad()方法中对这3个变量进行初始化,分别对应电影,音乐,图书页面
//根据Storyboard ID来创建一个View Controller
movieController = storyboard?.instantiateViewControllerWithIdentifier("MovieControllerID") as! MovieController
musicController = storyboard?.instantiateViewControllerWithIdentifier("MusicControllerID") as! MusicController
bookController = storyboard?.instantiateViewControllerWithIdentifier("BookControllerID") as! BookController
UIPageViewController是容器控制器,可是它自己却不知道应该包含哪些View Controller,所以要有别人来告诉它。借助UIPageViewControllerDataSource中的两个方法,告诉UIPageViewController应该在页面切换的时候,显示什么内容。在最后一个花括号的下方添加下面这段代码
extension MainController: UIPageViewControllerDataSource {
//返回当前页面的下一个页面
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
if viewController.isKindOfClass(MovieController) {
return musicController
}
else if viewController.isKindOfClass(MusicController) {
return bookController
}
return nil
}
//返回当前页面的上一个页面
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
if viewController.isKindOfClass(MusicController) {
return movieController
}
else if viewController.isKindOfClass(BookController) {
return musicController
}
return nil
}
}
接着回到viewDidLoad()方法,在它的最下方,添加两行代码,代码的作用可以从注释中看出
//设置pageViewController的数据源代理为当前Controller
pageViewController.dataSource = self
//手动为pageViewController提供提一个页面
pageViewController.setViewControllers([movieController], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
运行程序看看有什么效果,可以看到,用鼠标或者用手指(真机调试)左右滑动屏幕,有翻书的效果。到这里已经成功一半了,不过翻书的效果不是这里想要的,回到storyboard,找到Page View Controller,修改它的一个属性。
这里将Transition Style改为了scroll,这样做之后,页面之间的切换效果就变成水平滑动了。
是时候为电影,音乐,图书这3个页面填充点内容了
3.右键点击DataModel分组,新建一个Swift File,把它命名为CommonDataModel,在这个文件声明一个结构体,作为基本的数据模型
/**
* 基本数据模型, 包含图像地址和标题
*/
struct CommonDataModel {
var imageURL: String!
var title: String
init(imageURL: String, title: String) {
self.imageURL = imageURL
self.title = title
}
}
这个结构体很简单,一个存储图像地址的变量imageURL,和一个存储标题的变量title,还有一个构造方法
4.右键点击DataModel分组,创建3个Swift File文件,分别命名为MovieResults,MusicResults,BookResults。打开MovieResults.swift文件,添加下面这段代码
class MovieResults {
//存储电影信息的数组
var movies = [CommonDataModel]()
init(dicts: [NSDictionary]) {
//遍历字典数组,拿到图像地址,标题信息
//接着使用CommonDataModel创建一条电影记录
for dict in dicts {
let imageURL = (dict["images"] as! NSDictionary)["large"] as! String
let title = dict["title"] as! String
let movie = CommonDataModel(imageURL: imageURL, title: title)
movies.append(movie)
}
}
}
这是存储电影结果的类,movies变量用来保存电影记录,从豆瓣平台返回的数据经过解析之后,电影信息就是一个字典数组,因此这里遍历字典数组来创建电影记录,并添加到movies数组中
5.存储音乐结果和图书结果的类,和MovieResults类似。现在分别在MusicResults.swift和BookResults.swift文件中,添加下面的两段代码。
class MusicResults {
var musics = [CommonDataModel]()
init(dicts: [NSDictionary]) {
for dict in dicts {
let imageURL = dict["image"] as! String
let title = dict["title"] as! String
let music = CommonDataModel(imageURL: imageURL, title: title)
musics.append(music)
}
}
}
class BookResults {
var books = [CommonDataModel]()
init(dicts: [NSDictionary]) {
for dict in dicts {
let imageURL = (dict["images"] as! NSDictionary)["large"] as! String
let title = dict["title"] as! String
let book = CommonDataModel(imageURL: imageURL, title: title)
books.append(book)
}
}
}
6.接着打开MovieController.swift文件,声明一个MovieResult类型的实例变量,添加在movieTableView outlet的下方
@IBOutlet var movieTableView: UITableView!
var movieResults: MovieResults?
7.在import UIKit的下方添加一个import语句
import SDWebImage
,这条语句引入了SDWebImage模块,借助它可以方便的加载网络图片
8.为movieTableView注册一个可重用的Cell,这个Cell就是前面用XIB文件中的样子。把下面这段代码添加到viewDidLoad()方法中
movieTableView.registerNib(UINib(nibName: "CommonCell", bundle: nil), forCellReuseIdentifier: "CommonCell")
9.实现UITableViewDataSource的方法,为movieTableView提供数据,在最后一个花括号的地方,添加下面这段代码
extension MovieController: UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let result = moviesResult {
return result.movies.count
}
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let movie = moviesResult!.movies[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("CommonCell", forIndexPath: indexPath) as! CommonCell
cell.coverImageView.sd_setImageWithURL(NSURL(string: movie.imageURL))
cell.titleLabel.text = movie.title
return cell
}
}
- 上面的代码比较容易看懂,如果moviesResult是nil的话,返回的行数为0,不是nil的话就返回movies记录的数量。
- 在func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 方法中拿到对应的电影记录,根据ReuseIdentifier从cell的重用池中获取想要的Cell类型,这里是在前面创建的CommonCell。
- 接着为cell填充图片和标题
10.在viewDidLoad()方法中设置movieTableView的数据源代理为当前类
movieTableView.dataSource = self
11.到现在为止都还没有去获取豆瓣上的数据,接下来就去获取豆瓣上的数据,看可不可以在movieTableView中显示出来。在在viewDidLoad()方法的最下面添加下面这段代码
GetDataFromDouBan.getData("https://api.douban.com/v2/movie/search", type: "subjects", keyword: "张艺谋") { (data) -> Void in
self.movieResults = MovieResults(dicts: data)
self.movieTableView.reloadData()
}
借助帮助类GetDataFromDouBan的静态方法getData()去获取电影数据
运行之后,可以看到和下面截图类似的结果
11.看到这个说明离成功只有一步之遥了,只是cell的高度太小了,接着实现UITableViewDelegate中的方法,来调整cell的高度。在MovieController.swift文件的最下方,添加这段代码
//MARK: - UITableViewDelegate
extension MovieController: UITableViewDelegate {
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
最后在回到viewDidLoad()方法,在movieTableView.dataSource = self的下面,添加一句代码,设置movieTableView的代理为当前类
movieTableView.delegate = self
再运行一次看看效果,比上一次好多了
此时整个MovieController.swift代码文件的内容,应该和下面的类似
import UIKit
import SDWebImage
class MovieController: UIViewController {
@IBOutlet var movieTableView: UITableView!
var movieResults: MovieResults?
override func viewDidLoad() {
super.viewDidLoad()
movieTableView.registerNib(UINib(nibName: "CommonCell", bundle: nil), forCellReuseIdentifier: "CommonCell")
movieTableView.dataSource = self
movieTableView.delegate = self
GetDataFromDouBan.getData("https://api.douban.com/v2/movie/search", type: "subjects", keyword: "张艺谋") { (data) -> Void in
self.movieResults = MovieResults(dicts: data)
self.movieTableView.reloadData()
}
}
}
//MARK: - UITableViewDataSource
extension MovieController: UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let result = movieResults {
return result.movies.count
}
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let movie = movieResults!.movies[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("CommonCell", forIndexPath: indexPath) as! CommonCell
cell.coverImageView.sd_setImageWithURL(NSURL(string: movie.imageURL))
cell.titleLabel.text = movie.title
return cell
}
}
//MARK: - UITableViewDelegate
extension MovieController: UITableViewDelegate {
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
12.实现了一个页面,接下来就好办多了,因为剩下的两个页面几乎一摸一样,下面分别是MusicController.swift和BookController.swift代码文件的内容
import UIKit
class MusicController: UIViewController {
@IBOutlet var musicTableView: UITableView!
var musicResults: MusicResults?
override func viewDidLoad() {
super.viewDidLoad()
musicTableView.registerNib(UINib(nibName: "CommonCell", bundle: nil), forCellReuseIdentifier: "CommonCell")
musicTableView.dataSource = self
musicTableView.delegate = self
GetDataFromDouBan.getData("https://api.douban.com/v2/music/search", type: "musics", keyword: "梁静茹") { (data) -> Void in
self.musicResults = MusicResults(dicts: data)
self.musicTableView.reloadData()
}
}
}
extension MusicController: UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let result = musicResults {
return result.musics.count
}
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let music = musicResults!.musics[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("CommonCell", forIndexPath: indexPath) as! CommonCell
cell.coverImageView.sd_setImageWithURL(NSURL(string: music.imageURL))
cell.titleLabel.text = music.title
return cell
}
}
extension MusicController: UITableViewDelegate {
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
import UIKit
class BookController: UIViewController {
@IBOutlet var bookTableView: UITableView!
var bookResults: BookResults?
override func viewDidLoad() {
super.viewDidLoad()
bookTableView.registerNib(UINib(nibName: "CommonCell", bundle: nil), forCellReuseIdentifier: "CommonCell")
bookTableView.dataSource = self
bookTableView.delegate = self
GetDataFromDouBan.getData("https://api.douban.com/v2/book/search", type: "books", keyword: "swift") { (data) -> Void in
self.bookResults = BookResults(dicts: data)
self.bookTableView.reloadData()
}
}
}
extension BookController: UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let result = bookResults {
return result.books.count
}
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let music = bookResults!.books[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("CommonCell", forIndexPath: indexPath) as! CommonCell
cell.coverImageView.sd_setImageWithURL(NSURL(string: music.imageURL))
cell.titleLabel.text = music.title
return cell
}
}
extension BookController: UITableViewDelegate {
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
几乎和MovieController.swift的代码内容一摸一样,只是请求数据的地方不同。运行后,左右滑动,能够在电影,音乐,图书页面之间切换。
13.这个demo就快要完成了,最后只剩下装点的当前页面提示条了。找一张条形图片来当作提示条,把它拖到图片资源文件夹中,把图片命名为slider
14.回到storyboard找到Main Controller,我们的主控制器,打开辅助视图,为包含提示条的View生成对应的outlet,把它命名为sliderView
15.为3个button生成一个Action,这个3个button都会出发这个Action,因为button的tag属性有不同的值,所以根据tag值,可以知道点击了哪个button。选中电影button,按住control键,用鼠标左键拖向代码视图中,生成相应的action,把action命名为changeCurrentPage。完成后把另外两个button也关联到这个action
16.回到MainController.swift代码文件中,把提示条添加到页面中
- 在viewDidLoad()方法的上方添加一个变量,引用提示条图片
var sliderImageView: UIImageView!
- 在viewDidLoad()方法中的最下方,添加下面这段代码,把提示条添加到页面上
//添加提示条到页面中
sliderImageView = UIImageView(frame: CGRect(x: 0, y: -1, width: self.view.frame.width / 3.0, height: 3.0))
sliderImageView.image = UIImage(named: "slider")
sliderView.addSubview(sliderImageView)
运行可以看到,提示条已经成功添加上去了 ![](http://upload-images.jianshu.io/upload_images/706606-e8d5cdcddb76911f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
17.为了能够正确的使用button切换不同的页面,以及同步提示条的位置,需要两个变量来记录当前页面和上一个页面的索引,还要一个包含3个页面的数组
在bookController实例变量的下方声明一个数组变量
var bookController: BookController!
var controllers = [UIViewController]() //添加的代码
在viewDidLoad()方法中把3个页面添加到数组中
//把页面添加到数组中
controllers.append(movieController)
controllers.append(musicController)
controllers.append(bookController)
接着在viewDidLoad()方法的上方添加两个变量,索引当前页面和上一个页面
var lastPage = 0
var currentPage: Int = 0 {
didSet {
//根据当前页面计算得到便宜量
//一个微小的动画移动提示条
let offset = self.view.frame.width / 3.0 * CGFloat(currentPage)
UIView.animateWithDuration(0.3) { () -> Void in
self.sliderImageView.frame.origin = CGPoint(x: offset, y: -1)
}
//根据currentPage 和 lastPage的大小关系,控制页面的切换方向
if currentPage > lastPage {
self.pageViewController.setViewControllers([controllers[currentPage]], direction: .Forward, animated: true, completion: nil)
}
else {
self.pageViewController.setViewControllers([controllers[currentPage]], direction: .Reverse, animated: true, completion: nil)
}
lastPage = currentPage
}
}
currentPage有一个属性观察器,当currentPage的值被设置之后,改变提示条的位置,并根据currentPage 和 lastPage的大小关系,设置页面的切换方向(前进,后退)
18.设置currentPage的值,找到changeCurrentPage(sender: UIButton) action,在里面添加一句代码
//button的tag分别为100,101,102,减去100之后就对应页面的索引
currentPage = sender.tag - 100
这时运行一遍看看,点击不同的按钮可以切换到不同的页面,提示条也会跟着移动
此时还有一个问题,当滑动屏幕进行页面切换时,提示条没有跟着移动。
19,解决最后的问题------使用通知
打开MovieController.swift代码文件,在viewDidLoad()方法的下方,添加一个方法,这个方法会在页面出现时调用,在这个方法中发送一个页面改变的通知
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//发送一个名字为currentPageChanged,附带object的值代表当前页面的索引
NSNotificationCenter.defaultCenter().postNotificationName("currentPageChanged", object: 0)
}
在MusicController.swift和BookController.swift代码文件中添加相同的代码,不过把object的值分别改为1和2
20.回到MainController.swift代码文件,让MainController接收页面改变的通知,并对页面改变作出响应。把下面的代码添加viewDidLoad()方法中
//接收页面改变的通知
NSNotificationCenter.defaultCenter().addObserver(self, selector: "currentPageChanged:", name: "currentPageChanged", object: nil)
在接收到通知之后,会调用currentPageChanged(notification: NSNotification)方法,接下来,添加这个方法,在这个方法中设置currentPage的值
//通知响应方法
func currentPageChanged(notification: NSNotification) {
currentPage = notification.object as! Int
}
运行可以看到,滑动屏幕进行页面切换,提示条也会跟着移动
到这里这个demo就结束了,不是很难_ !!
总结
在这个demo中可以看到,多个水平层次的页面能够用UIPageViewController方便的管理。虽然这里的页面的布局和逻辑代码都几乎一样,可是却是各自独立的,这意味着,每个页面可以有不同的布局方式,不同的逻辑控制,而UIPageViewController仅仅是控制页面的切换,不会对页面自身造成影响。