第一次加载APP的时候通常会采用引导页来展示特色或者告知用户如何使用。打开我们的Storyboard,然后导入一个Page View Controller,作如下设置,修改Transition Style:
然后给我们的Page View Controller设置一个storyboard的ID为PageViewController。
现在你应该很想知道我们如何能编辑我们的pageviewcontroller,它看起来并不能被编辑,首先你需要知道它的原理。
page view controller被定义成一个view controller的管理者,组织并管理多张页面,而每张页面是要被它自己的view controller管理的。所以我们首先要添加一个view controller,你可能会好奇为什么我想做三张引导页却只新建一个view controller。是因为引导页的结构十分相似,我们可以服用页面上的组件。然后我们在viewcontroller中拖入两个label(文字居中,并且第二个label足够大)和一个imageview,如图:
然后给这个viewcontroller的storyboardID取为pagecontentviewcontroller,然后新建一个同名的类,在类中加入以下代码:
- @IBOutlet weak var headingLabel:UILabel!
- @IBOutlet weak var subHeadingLabel:UILabel!
- @IBOutlet weak var contentImageView:UIImageView!
- var index : Int = 0
- var heading : String = ""
- var imageFile : String = ""
- var subHeading : String = ""
这里的index用来表示引导页的顺序,比如第一张的index就是0
viewDidLoad方法中加入:
- headingLabel.text = heading
- subHeadingLabel.text = subHeading
- contentImageView.image = UIImage(named: imageFile)
之后在storyboard把代码中的label和image和界面中的连起来。
好了,现在内容的页面部分已经完成了,接着我们来实现页面的切换。把这些引导页加入到Page view Controller中,这样用户就可以切换它们了。我们可以使用on-demand 点播的方法来实现,在这个方法中,我们需要创建一个数据源,当用户切换的时候,数据源告诉我们的pageviewcontroller需要播放哪一张viewcontroller。数据源继承自PageViewControllerDataSource,需要实现下面这两个方法:
现在我们新建一个文件PageViewController,它的类型是UIPageViewController,继承PageViewControllerDataSource。
- var pageHeadings = ["摇出美食","地图定位","美食共享"]
- var pageImages = ["fiveleaves","mapintro","homei"]
- var pageSubHeadings = ["摇出心中所想,轻松搞定美食","寻找心仪的饭馆,SoFun为你导航","共享你的发现,建立吃货友谊"]
实现两个代理方法:
- func pageViewController(pageViewController: UIPageViewController,viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
- var index = (viewController as PageContentViewController).index
- index++
- return self.viewControllerAtIndex(index)
- }
- func pageViewController(pageViewController: UIPageViewController,viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
- var index = (viewController as PageContentViewController).index
- index--
- return self.viewControllerAtIndex(index)
- }
当我们前进或者后退的时候首先获得当前页面的index值然后自增或者自减,将相邻的页面返回。
- func viewControllerAtIndex(index: Int) -> PageContentViewController? {
- if index == NSNotFound || index < 0 || index >= self.pageHeadings.count {
- return nil
- }
- // Create a new view controller and pass suitable data.
- if let pageContentViewController = storyboard?.instantiateViewControllerWithIdentifier("PageContentViewController") as? PageContentViewController {
- pageContentViewController.imageFile = pageImages[index]
- pageContentViewController.heading = pageHeadings[index]
- pageContentViewController.subHeading = pageSubHeadings[index]
- pageContentViewController.index = index
- return pageContentViewController
- }
- return nil
- }
在viewDidLoad方法中加入以下代码:
- // Set the data source to itself
- dataSource = self
- // Create the first walkthrough screen
- if let startingViewController = self.viewControllerAtIndex(0) {
- setViewControllers([startingViewController],direction: .Forward,animated: true,completion: nil)
- }
现在我们的引导页基本完工了,我们要把引导页放到程序的第一个页面之前,在你的第一个页面的代码的viewDidLoad方法中加入如下代码:
- if let pageViewController = storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as? PageViewController {
- self.presentViewController(pageViewController,completion: nil)
- }
可以运行一下看看了!
通过滑动可以切换
我们现在来增加一些控制,再在pageviewcontroller中加入下面两个方法:
- func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
- return pageHeadings.count
- }
- func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
- if let pageContentViewController = storyboard?.instantiateViewControllerWithIdentifier("PageContentViewController") as? PageContentViewController {
- return pageContentViewController.index
- }
- return 0
- }
运行一下看看屏幕下方:
可以看到调用系统自带的页面指示器很容易实现,但是它的风格是固定的,我们想要自己定义一款指示器。
把上面那段代码注释掉,然后我们去storyboard中拖拽一个page control到heading的顶部
设置它的背景色和选中的颜色如下:
现在页面上的控制器如图:
在pagecontentviewcontroller中加入对应的对象,然后关联:
在viewDidLoad方法中加入以下代码标示当前的页面数:
- @IBOutlet weak var pageControl:UIPageControl!
- pageControl.currentPage = index
页面指示器有了,之前我们靠着滑动页面来切换并且无法切出,现在我们增加一个按钮,来实现页面切换和切出。
按钮的样式自己设计
继续与类关联,我这里开始体验的按钮用了第三方的库,所以不是UIButton,效果是一样的。
- @IBOutlet weak var getStartedButton:MKButton!
- @IBOutlet weak var forwardButton:UIButton!
在viewDidLoad中增加以下代码:
- getStartedButton.hidden = (index == 2) ? false : true
- forwardButton.hidden = (index == 2) ? true: false
前两页显示forward按钮,最后一页隐藏forward按钮,显示“开始体验”按钮。
- @IBAction func close(sender: AnyObject) {
- dismissViewControllerAnimated(true,completion: nil)
- }
- @IBAction func nextScreen(sender: AnyObject) {
- let pageViewController = self.parentViewController as PageViewController
- pageViewController.forward(index)
- }
}
@IBAction func nextScreen(sender: AnyObject) { let pageViewController = self.parentViewController as PageViewController pageViewController.forward(index) }nextScreen方法中调用了pageViewController中的forward这个辅助方法,这个方法还没有实现,现在回到pageViewController中,加入以下代码:
- func forward(index: Int) {
- if let nextViewController = self.viewControllerAtIndex(index + 1) {
- setViewControllers([nextViewController],completion: nil)
- }
- }
现在运行一下看看效果吧!
现在就剩最后一个问题了:保证引导页只在第一次打开时出现。IOS的SDK中有一个类NSUserDefault,来映射应用和用户的设置,比如你可以用它来保存一个状态位用来判断是否需要启动引导页。再比如用户标示了一个价格,而你也可以用这个类来记录用户标示这个价格使用的货币类型。NSUserDefault类使用了与操作系统相关联的借口,也就是说你在其中配置的数据在APP关闭时依旧起作用。现在我们需要重新写close方法,关闭了一次后用户的使用状况就改变了:
- @IBAction func close(sender: AnyObject) {
- let defaults = NSUserDefaults.standardUserDefaults()
- defaults.setBool(true,forKey: "hasViewedWalkthrough")
- dismissViewControllerAnimated(true,completion: nil)
- }
我们给一个key值为“hasViewedWalkthrough”的系统量设置了布尔值,当引导页运行过一次后它变为true,现在在我们系统的第一张页面的viewDidLoad方法中修改如下:
好了大功告成,快来试试吧!
- let hasViewedWalkthrough = defaults.boolForKey("hasViewedWalkthrough")
- if hasViewedWalkthrough == false {
- if let pageViewController = storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as? PageViewController {
- self.presentViewController(pageViewController,completion: nil)
- }
- }