天天看點

swift+UIPageViewController 純代碼實作引導頁

使用UIPageViewController

1、介紹:

UIPageViewController是一個類似UINavigationController的Controller容器。它既可以實作UIScrollView的滑動效果,也可以實作UIPageController的翻頁效果。其中每個具體的視圖由各自的ViewController進行維護管理,UIPageViewController隻進行協調與動畫布置。

UIPageViewControllerDataSource協定為UIPageViewController提供資料,UIPageViewControllerDelegate對翻頁動作、螢幕旋轉進行監聽。

2、代碼:
/// 引導頁
class YSGuidePageViewController: UIPageViewController,UIPageViewControllerDelegate,UIPageViewControllerDataSource {

    /// 頁面數量改變時的回調
    var pageViewControllerUpdatePageCount:((YSGuidePageViewController,NSInteger)->Void)!
    /// 頁面改變時的回調
    var pageViewControllerUpdatePageIndex:((YSGuidePageViewController,NSInteger)->Void)!

    private(set) lazy var allViewControllers:[UIViewController]={
        return [YSGuideImgViewController(imgName: "guide_pic_new1",frame: self.view.bounds, showBtn:false),
                YSGuideImgViewController(imgName: "guide_pic_new2",frame: self.view.bounds, showBtn:false),
                YSGuideImgViewController(imgName: "guide_pic_new3",frame: self.view.bounds,showBtn:true)]
    }()

    internal init(transitionStyle style: UIPageViewControllerTransitionStyle, navigationOrientation: UIPageViewControllerNavigationOrientation, options: [String : AnyObject]?, pageCount:((YSGuidePageViewController,NSInteger)->Void)!, pageIndex:((YSGuidePageViewController,NSInteger)->Void)!) {
        super.init(transitionStyle: style, navigationOrientation: navigationOrientation, options: options)
        self.pageViewControllerUpdatePageCount = pageCount
        self.pageViewControllerUpdatePageIndex = pageIndex
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self
        dataSource = self
        //設定首頁
        if let firstViewController = allViewControllers.first {
            setViewControllers([firstViewController], direction: .Forward, animated: true, completion:nil)
        }

        //頁面數量改變時
        if self.pageViewControllerUpdatePageCount != nil {
            self.pageViewControllerUpdatePageCount(self,allViewControllers.count)
        }
    }

    //mark:擷取前一個頁面
    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        //guard 條件為false就執行else裡的函數塊
        guard let viewControllerIndex = allViewControllers.indexOf(viewController) else {
            return nil
        }
        let previousIndex = viewControllerIndex - 
        guard previousIndex >=  else {
            return nil
        }
        guard allViewControllers.count > previousIndex else {
            return nil
        }
        return allViewControllers[previousIndex]
    }

    //mark:擷取後一個頁面
    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = allViewControllers.indexOf(viewController) else {
            return nil
        }
        let nextIndex = viewControllerIndex + 
        let orderedViewControllersCount = allViewControllers.count
        guard orderedViewControllersCount != nextIndex else {
            return nil
        }
        guard orderedViewControllersCount>nextIndex else {
            return nil
        }
        return allViewControllers[nextIndex]
    }

    //mark:頁面切換完畢
    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        if let firstViewController = viewControllers?.first,let index = allViewControllers.indexOf(firstViewController) {
            if self.pageViewControllerUpdatePageIndex != nil {
                self.pageViewControllerUpdatePageIndex(self,index)
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}





/// 具體承載引導圖檔的VC
class YSGuideImgViewController: UIViewController {

    private(set) lazy var imgview:UIImageView = {
        return UIImageView.init(frame:self.view.bounds)
    }()

    private(set) lazy var beginBtn:UIButton = {
        return UIButton(type:.Custom)
    }()
    /**
     重寫了初始化方法

     - parameter imgName: 使用到的圖檔名稱
     - parameter frame:   圖檔的frame
     - parameter showBtn: 是否展示開始體驗的按鈕

     - returns:
     */
    init(imgName:String, frame:CGRect, showBtn:Bool){
        super.init(nibName: nil, bundle: nil)
        self.view.frame = frame
        self.view.addSubview(self.imgview)
        self.imgview.image = UIImage(named: imgName)

        self.beginBtn.frame = CGRectMake((self.view.bounds.width-)/, self.view.bounds.height--, , )
        self.beginBtn.setImage(UIImage(named:"home_btn_startup"), forState: .Normal)
        self.beginBtn.addTarget(self, action:#selector(beginBtnClicked), forControlEvents: .TouchUpInside)
        self.view.addSubview(self.beginBtn)
        self.beginBtn.hidden = !showBtn
    }

    /**
     按鈕點選事件
     */
    func beginBtnClicked() {
        NSNotificationCenter.defaultCenter().postNotificationName("beginExperience", object: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}





/// 加載PageViewController的VC
class YSGuideViewController: YSBaseController {

    private(set) lazy var pageControl:UIPageControl = {
        return UIPageControl(frame:CGRectMake((self.view.bounds.width-)/,self.view.bounds.height--,,))
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(removeGuidePageView), name: "beginExperience", object: nil)

        self.view.backgroundColor = UIColor(patternImage:UIImage(named: "launch_bg")!)
        self.view.addSubview(pageControl)
        pageControl.backgroundColor = UIColor.clearColor()
        pageControl.pageIndicatorTintColor = UIColor.whiteColor()
        pageControl.currentPageIndicatorTintColor = UIColor.redColor()
        loadGuidePageView()
    }

    func loadGuidePageView() {

        let guideview = YSGuidePageViewController.init(transitionStyle: .PageCurl, navigationOrientation: .Horizontal, options: nil, pageCount: { (guide:YSGuidePageViewController, count:NSInteger) in
            self.pageControl.numberOfPages = count
            },pageIndex: {(guide:YSGuidePageViewController, index:NSInteger) in
                self.pageControl.currentPage = index
        })//Scroll
        guideview.view.frame = self.view.bounds
        self.view.addSubview(guideview.view)
        self.addChildViewController(guideview)

        self.view.bringSubviewToFront(pageControl)
    }


    /**
     移除引導頁,同時記錄引導頁已經顯示完成
     */
    func removeGuidePageView() {

        self.view.removeFromSuperview()
        self.removeFromParentViewController()
        //Todo:存儲第一次已經顯示引導頁

    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
           
3、實作提醒:

1、首先使用的過程中出現的一個最大最無語的問題就是UIPageViewController的代理不執行,而且隻有一個引導頁。

出現這個問題的原因是在YSGuideViewController中使用的時候忘記寫 self.addChildViewController(guideview) ,是以這個狠重要。