若要在一個頁面中使用 SegmentedControl 和 PageViewController 來轉換頁面該如何實作呢?
Step 1: 製作畫面
在主頁面上增加控制項 Segmented Control

新增兩個ViewController頁面,
並設置storyboard id 為firstPage, secondPage

Step 2: Reference SegmentedControl
在ViewController.swift中, 設置SegmentedControl物件和點擊事件.

使用UISegmentedControl.selectedSegmentIndex可得知目前所按到的tab為何
Step 3: 設置 PageViewController
設置PageView內容

新增PageViewController
1
| var pageController: UIPageViewController!
|
使用水平滾動的方式變換頁面
1
| pageController = UIPageViewController(transitionStyle: .Scroll, navigationOrientation:.Horizontal, options: nil)
|
設置PageView顯示位置
1
| pageController!.view.frame = CGRectMake(0, mPageSegment.frame.origin.y + mPageSegment.frame.height, view.frame.size.width, view.frame.size.height);
|
設置首頁
1 2
| currentPageIndex = 0; pageController.setViewControllers([viewControllers.objectAtIndex(currentPageIndex) as! UIViewController], direction: .Forward, animated: false) {(isFinished:Bool) -> Void in}
|
監聽頁面變化 UIPageViewControllerDelegate及頁面資料UIPageViewControllerDataSource
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| pageController.delegate = self; pageController.dataSource = self;
extension ViewController: UIPageViewControllerDataSource { func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
return nil }
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
return nil } }
extension ViewController: UIPageViewControllerDelegate { func pageViewController(pageViewController: UIPageViewController,
} }
|
將PageViewController新增至畫面中
1 2
| self.addChildViewController(pageController) self.view.addSubview(pageController.view)
|
Step 4: 設置轉換頁面的資料
由左至右滑動時, 也就是往前翻頁, 若前頁的上一頁的頁數小於0時, 則回傳nil
(若目前第二頁時, 往前翻頁為第一頁, 而第一頁的前頁為nil)
1 2 3 4 5 6 7 8 9
| func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? { currentPageIndex = viewController.view.tag let pageIndex = viewController.view.tag - 1; if pageIndex < 0 { return nil } return viewControllers[pageIndex] as? UIViewController }
|
由右至左滑動時, 也就是往後翻頁, 若後頁的下一頁的頁數大於總頁數時, 則回傳nil
(若目前第一頁時, 往後翻頁為第二頁, 而第二頁的下頁為nil)
1 2 3 4 5 6 7 8 9
| func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? { currentPageIndex = viewController.view.tag let pageIndex = viewController.view.tag + 1; if pageIndex > 1 { return nil }
return viewControllers[pageIndex] as? UIViewController }
|
以上我們完成了PageViewController的控制, 接下來要結合Segmented Controll來控制PageView
Step 5: Segment的變換
對於SegmentControll的變換, 使用SegmentControll.selectedSegmentIndex來改變選取的Tab
在Step 4 的兩個步驟中, 加入 mPageSegment.selectedSegmentIndex = currentPageIndex;

Step 6: 點擊SegmentControll來改變PageView
之前發生過使用點擊來轉換頁面太快時, 會出NSInternalInconsistencyException
原因是切換PageView時設定了轉移動畫, 當動畫還未結束時, 又再一次要求改變PageView所導致.
解決方式:
轉換PageView時, 不設定動畫
1
| pageController!.setViewControllers([self.viewControllers[index] as! UIViewController], direction: .Reverse, animated: false, completion:nil)
|
必須等動畫完成後, 才能再轉換PageView
在此我們採用第二種方式, 當點擊SegmentedControll時, 將enabled設為false.
動畫結束後再設定為true.
設定轉換動畫
若當前頁碼小於選擇頁碼時 (往前翻頁)
direction: UIPageViewControllerNavigationDirection.Forward
若當前頁碼大於選擇頁碼時 (往後翻頁)
direction: UIPageViewControllerNavigationDirection.Reverse
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @IBAction func tapSegment(sender: AnyObject) { mPageSegment.enabled = false;
let index = (sender as! UISegmentedControl).selectedSegmentIndex; if (currentPageIndex < index) { pageController!.setViewControllers([self.viewControllers[index] as! UIViewController], direction: .Forward, animated: true, completion:{(isFinished: Bool) in self.mPageSegment.enabled = true; }) } else { pageController!.setViewControllers([self.viewControllers[index] as! UIViewController], direction: .Reverse, animated: true, completion:{(isFinished: Bool) in self.mPageSegment.enabled = true; }) }
currentPageIndex = index }
|
使用滑動翻頁時, 當動畫結束後, 須將SegmentControll.enabled設為true
1 2 3 4 5
| extension ViewController: UIPageViewControllerDelegate { func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { mPageSegment.enabled = true; } }
|
Source Code
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| import UIKit
class ViewController: UIViewController { @IBOutlet weak var mPageSegment: UISegmentedControl! @IBAction func tapSegment(sender: AnyObject) { mPageSegment.enabled = false; let index = (sender as! UISegmentedControl).selectedSegmentIndex;
if (currentPageIndex < index) { pageController!.setViewControllers([self.viewControllers[index] as! UIViewController], direction: .Forward, animated: true, completion:{(isFinished: Bool) in self.mPageSegment.enabled = true; }) } else { pageController!.setViewControllers([self.viewControllers[index] as! UIViewController], direction: .Reverse, animated: true, completion:{(isFinished: Bool) in self.mPageSegment.enabled = true; }) } currentPageIndex = index }
var pageController: UIPageViewController! var viewControllers = NSMutableArray() var currentPageIndex : Int!
override func viewDidLoad() { super.viewDidLoad() let storyboard = UIStoryboard(name: "Main", bundle: nil) let firstViewController = storyboard.instantiateViewControllerWithIdentifier("firstPage") firstViewController.view.tag = 0; viewControllers.addObject(firstViewController)
let secondViewController = storyboard.instantiateViewControllerWithIdentifier("secondPage") secondViewController.view.tag = 1; viewControllers.addObject(secondViewController)
pageController = UIPageViewController(transitionStyle: .Scroll, navigationOrientation:.Horizontal, options: nil)
pageController!.view.frame = CGRectMake(0, mPageSegment.frame.origin.y + mPageSegment.frame.height, view.frame.size.width, view.frame.size.height); currentPageIndex = 0; pageController.setViewControllers([viewControllers.objectAtIndex(currentPageIndex) as! UIViewController], direction: .Forward, animated: false) {(isFinished:Bool) -> Void in }
pageController.delegate = self; pageController.dataSource = self;
self.addChildViewController(pageController) self.view.addSubview(pageController.view) }
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
extension ViewController: UIPageViewControllerDataSource { func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? { currentPageIndex = viewController.view.tag mPageSegment.selectedSegmentIndex = currentPageIndex; let pageIndex = viewController.view.tag - 1; if pageIndex < 0 { return nil } return viewControllers[pageIndex] as? UIViewController }
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? { currentPageIndex = viewController.view.tag mPageSegment.selectedSegmentIndex = currentPageIndex; let pageIndex = viewController.view.tag + 1; if pageIndex > 1 { return nil } return viewControllers[pageIndex] as? UIViewController } }
extension ViewController: UIPageViewControllerDelegate { func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { mPageSegment.enabled = true; } }
|
執行結果


