iPhone/Swift 2.0

swift viewpager 개발하기

코딩저장소 2016. 3. 4. 15:07


AViewController.swift


BViewController.swift


CViewController.swift


PagerViewController.swift

https://spin.atomicobject.com/2015/12/23/swift-uipageviewcontroller-tutorial/


How to Use UIPageViewController in Swift

UIPageViewController is a powerful class used by nine out of ten of the apps you will ever come across. Many apps use it for feature lists and/or tips on getting started. In this post, I will show you how incredibly easy it is to make a UIPageViewController tutorial.

giphy-2

To start, let’s create a new application. It doesn’t matter which type you select, since we’re going to start with a clean slate anyway. Select a product name and be sure to select Swift for the language.

UIPageViewController 1

Remove all of the auto-generated files besides the ones listed.

Screen Shot 2015-12-11 at 8.52.46 AM

Now remove all of the objects in Main.storyboard. If you did everything right, building the project (Cmd + b) should succeed.

Untitled 2

Next, inside Main.storyboard, add a new Page View Controller object to the canvas.

Screen Shot 2015-12-11 at 9.01.36 AM

Make sure to set the new UIPageViewController object as the initial view controller in the attributes inspector. That way, it will be initialized when the app launches.

Main_storyboard_—_Edited

Next, let’s create a custom UIPageViewController subclass…

Screen Shot 2015-12-11 at 9.13.49 AM

…and assign it to the UIPageViewController object (which we created inside Main.storyboard earlier) in the identity inspector.

Screen Shot 2015-12-11 at 3.55.10 PM

Now for the fun part–let’s create three view controller objects inMain.storyboard. These will eventually be scrolled through in the page view controller.

Screen Shot 2015-12-11 at 4.04.24 PM

Planning ahead a bit, let’s set Storyboard IDs in the identity inspector for each of the view controllers above. These will be used in code to instantiate the view controllers. Alternatively, you could create three separate UIViewController subclass files and assign them to the objects in the storyboard.

Screen Shot 2015-12-11 at 4.12.07 PM

Screen Shot 2015-12-11 at 4.06.20 PM

Screen Shot 2015-12-11 at 4.06.26 PM

All right, now that our storyboard is all set up, let’s write some code! To start, let’s set ourselves as the datasource and define the required methods.

SWIFT
//
//  TutorialPageViewController.swift
//  UIPageViewController Post
//
//  Created by Jeffrey Burt on 12/11/15.
//  Copyright © 2015 Atomic Object. All rights reserved.
//

import UIKit

class TutorialPageViewController: UIPageViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        dataSource = self
    }
}
    
// MARK: UIPageViewControllerDataSource

extension TutorialPageViewController: UIPageViewControllerDataSource {
 
    func pageViewController(pageViewController: UIPageViewController, 
        viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
            return nil
    }
    
    func pageViewController(pageViewController: UIPageViewController, 
        viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
            return nil
    }
    
}

Next, let’s add an array to reference the view controllers we want to page through. The view controllers will be shown in this order.

SWIFT
private(set) lazy var orderedViewControllers: [UIViewController] = {
    return [self.newColoredViewController("Green"),
        self.newColoredViewController("Red"),
        self.newColoredViewController("Blue")]
}()

private func newColoredViewController(color: String) -> UIViewController {
    return UIStoryboard(name: "Main", bundle: nil) .
        instantiateViewControllerWithIdentifier("\(color)ViewController")
}

Now, it’s time to load up the first view controller (green).

SWIFT
override func viewDidLoad() {
    super.viewDidLoad()
        
    dataSource = self
        
    if let firstViewController = orderedViewControllers.first {
        setViewControllers([firstViewController],
            direction: .Forward,
            animated: true,
            completion: nil)
    }
}

Sweet, green is shown, but what about red and blue? Let’s go ahead and actually implement the UIPageViewControllerDataSource methods to get swiping up and running.

SWIFT
func pageViewController(pageViewController: UIPageViewController,
    viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = orderedViewControllers.indexOf(viewController) else {
            return nil
        }
        
        let previousIndex = viewControllerIndex - 1
        
        guard previousIndex >= 0 else {
            return nil
        }
        
        guard orderedViewControllers.count > previousIndex else {
            return nil
        }
        
        return orderedViewControllers[previousIndex]
}

func pageViewController(pageViewController: UIPageViewController,
    viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = orderedViewControllers.indexOf(viewController) else {
            return nil
        }
        
        let nextIndex = viewControllerIndex + 1
        let orderedViewControllersCount = orderedViewControllers.count

        guard orderedViewControllersCount != nextIndex else {
            return nil
        }
        
        guard orderedViewControllersCount > nextIndex else {
            return nil
        }
        
        return orderedViewControllers[nextIndex]
}

This gives us the following output:

1

This is great and all, but what if we wanted to loop the view controllers? Easy! Just convert the UIPageViewControllerDataSource methods to the following:

SWIFT
func pageViewController(pageViewController: UIPageViewController,
    viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = orderedViewControllers.indexOf(viewController) else {
            return nil
        }
        
        let previousIndex = viewControllerIndex - 1
        
        // User is on the first view controller and swiped left to loop to
        // the last view controller.
        guard previousIndex >= 0 else {
            return orderedViewControllers.last
        }
        
        guard orderedViewControllers.count > previousIndex else {
            return nil
        }
        
        return orderedViewControllers[previousIndex]
}

func pageViewController(pageViewController: UIPageViewController,
    viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = orderedViewControllers.indexOf(viewController) else {
            return nil
        }
        
        let nextIndex = viewControllerIndex + 1
        let orderedViewControllersCount = orderedViewControllers.count
        
        // User is on the last view controller and swiped right to loop to
        // the first view controller.
        guard orderedViewControllersCount != nextIndex else {
            return orderedViewControllers.first
        }
        
        guard orderedViewControllersCount > nextIndex else {
            return nil
        }
        
        return orderedViewControllers[nextIndex]
}

Sweet, an infinite loop that we actually want!

giphy

But we’re making a tutorial. Let’s trash the page curl and replace it with a horizontal scroll. This can be done in the attributes inspector insideMain.storyboard. Be sure to click on the Tutorial Page View Controllerobject since that’s what we’re editing.

555

giphy-1

There’s only one thing missing: the dots! Simply implement the following two UIPageViewControllerDataSource methods inside ourTutorialPageViewController: UIPageViewControllerDataSource extension.

SWIFT
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
    return orderedViewControllers.count
}

func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
    guard let firstViewController = viewControllers?.first,
        firstViewControllerIndex = orderedViewControllers.indexOf(firstViewController) else {
            return 0
    }
    
    return firstViewControllerIndex
}

Build and run and you should be all set! And for the best part…theGitHub Download link!

Update: Be sure to check out my next post, where I explain How to Move Page Dots in a UIPageViewController.

Screen Shot 2016-02-03 at 11.06.50 AM










-----------------------------------------------------

import UIKit


/// Page delegate protocol

///

/// This is a protocol implemented by all of the child view controllers. I'm using it

/// just to keep track of the page number. In practical usage, you might also pass a

/// reference to a model object, too.


@objc protocol PageDelegate {

    var pageNumber: Int { get set }

}


class PagerViewController: UIPageViewController, UIPageViewControllerDataSource {

    

    private let identifiers = ["A", "B", "C"// the storyboard ids for the four child view controllers

    private var cache = NSCache()

    private var observer: NSObjectProtocol!

    

    override func viewDidLoad() {

        super.viewDidLoad()

        

        observer = NSNotificationCenter.defaultCenter().addObserverForName(UIApplicationDidReceiveMemoryWarningNotification, object: nil, queue: NSOperationQueue.mainQueue()) { [unowned self] notification in

            self.cache.removeAllObjects()

        }

        self.dataSource = self

        

        setViewControllers([viewControllerForPage(0)!], direction: .Forward, animated: false, completion: nil)

    }

    

    deinit {

        NSNotificationCenter.defaultCenter().removeObserver(observer)

    }

    

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {

        let page = (viewController as! PageDelegate).pageNumber + 1

        

        return viewControllerForPage(page)

    }

    

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {

        let page = (viewController as! PageDelegate).pageNumber - 1

        

        return viewControllerForPage(page)

    }

    

    private func viewControllerForPage(page: Int) -> UIViewController? {

        if page >= 0 && page < identifiers.count {

            if let controller = cache.objectForKey(page) as? UIViewController {

                return controller

            }

            if let controller = storyboard?.instantiateViewControllerWithIdentifier(identifiers[page]) {

                (controller as? PageDelegate)?.pageNumber = page

                cache.setObject(controller, forKey: page)

                return controller

            }

        }

        

        return nil

    }

}






----------------

import UIKit


class AViewController: UIViewController, PageDelegate {


    var pageNumber: Int = 0


}




import UIKit


class BViewController: UIViewController, PageDelegate {


    var pageNumber: Int = 0


}




import UIKit


class CViewController: UIViewController, PageDelegate {


    var pageNumber: Int = 0


}