Skip to content

Instantly share code, notes, and snippets.

@andreif
Created March 16, 2016 22:15
Show Gist options
  • Save andreif/3bace9961c7e70995856 to your computer and use it in GitHub Desktop.
Save andreif/3bace9961c7e70995856 to your computer and use it in GitHub Desktop.
Example of UIPageViewController without storyboard i.e. created programmatically
// derived from https://www.veasoftware.com/posts/uipageviewcontroller-in-swift-xcode-62-ios-82-tutorial
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window!.rootViewController = ViewController()
window!.makeKeyAndVisible()
return true
}
}
struct Page {
var title: String
var image: String
}
let PAGES = [
Page(title: "Explore", image: "https://i.imgur.com/FGknouw.png"),
Page(title: "Today Widget", image: "https://i.imgur.com/feuwhEc.png"),
]
class ViewController: UIViewController {
var pageViewController: UIPageViewController!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor()
let pc = UIPageControl.appearance()
pc.pageIndicatorTintColor = UIColor.lightGrayColor()
pc.currentPageIndicatorTintColor = UIColor.blackColor()
pc.backgroundColor = UIColor.whiteColor()
let btn = UIButton(type: .System)
btn.setTitle("Restart", forState: .Normal)
btn.addTarget(self, action: "restartAction:", forControlEvents: .TouchUpInside)
self.pageViewController = UIPageViewController(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: nil)
self.pageViewController.dataSource = self
self.restartAction(self)
self.addChildViewController(self.pageViewController)
let views = [
"pg": self.pageViewController.view,
"btn": btn,
]
for (_, v) in views {
v.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(v)
}
NSLayoutConstraint.activateConstraints(
[NSLayoutConstraint(
item: btn,
attribute: .CenterX,
relatedBy: .Equal,
toItem: self.view,
attribute: .CenterX,
multiplier: 1,
constant: 0),
] +
NSLayoutConstraint.constraintsWithVisualFormat("H:|[pg]|", options: .AlignAllCenterX, metrics: [:], views: views) +
NSLayoutConstraint.constraintsWithVisualFormat("V:|-30-[pg]-[btn]-15-|", options: .AlignAllCenterX, metrics: [:], views: views)
)
self.pageViewController.didMoveToParentViewController(self)
}
func restartAction(sender: AnyObject) {
self.pageViewController.setViewControllers([self.viewControllerAtIndex(0)], direction: .Forward, animated: true, completion: nil)
}
func viewControllerAtIndex(index: Int) -> ContentViewController {
if (PAGES.count == 0) || (index >= PAGES.count) {
return ContentViewController()
}
let vc = ContentViewController()
vc.pageIndex = index
return vc
}
}
// MARK: - Page View Controller Data Source
extension ViewController: UIPageViewControllerDataSource {
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let vc = viewController as! ContentViewController
var index = vc.pageIndex as Int
if (index == 0 || index == NSNotFound) {
return nil
}
index--
return self.viewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let vc = viewController as! ContentViewController
var index = vc.pageIndex as Int
if (index == NSNotFound) {
return nil
}
index++
if (index == PAGES.count) {
return nil
}
return self.viewControllerAtIndex(index)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return PAGES.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
}
class ContentViewController: UIViewController {
var pageIndex: Int!
override func viewDidLoad() {
super.viewDidLoad()
let lb = UILabel()
lb.textAlignment = .Center
lb.text = PAGES[self.pageIndex].title
let iv = UIImageView()
iv.contentMode = .ScaleAspectFit
ImageLoader.sharedLoader.imageForUrl(PAGES[self.pageIndex].image) { (image, url) -> () in
iv.image = image
}
let views = [
"iv": iv,
"lb": lb,
]
for (_, v) in views {
v.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(v)
}
NSLayoutConstraint.activateConstraints(
NSLayoutConstraint.constraintsWithVisualFormat("H:|-[lb]-|", options: .AlignAllCenterX, metrics: [:], views: views) +
NSLayoutConstraint.constraintsWithVisualFormat("H:|-[iv]-|", options: .AlignAllCenterX, metrics: [:], views: views) +
NSLayoutConstraint.constraintsWithVisualFormat("V:|-[lb]-[iv]-|", options: .AlignAllCenterX, metrics: [:], views: views)
)
}
}
class ImageLoader {
// source and license: https://github.com/natelyman/SwiftImageLoader
let cache = NSCache()
class var sharedLoader : ImageLoader {
struct Static {
static let instance : ImageLoader = ImageLoader()
}
return Static.instance
}
func imageForUrl(urlString: String, completionHandler: (image: UIImage?, url: String) -> ()) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {()in
let data = self.cache.objectForKey(urlString) as? NSData
if let goodData = data {
let image = UIImage(data: goodData)
dispatch_async(dispatch_get_main_queue(), {() in
completionHandler(image: image, url: urlString)
})
return
}
let downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: {(data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
if (error != nil) {
completionHandler(image: nil, url: urlString)
return
}
if let data = data {
let image = UIImage(data: data)
self.cache.setObject(data, forKey: urlString)
dispatch_async(dispatch_get_main_queue(), {() in
completionHandler(image: image, url: urlString)
})
return
}
})
downloadTask.resume()
})
}
}
@gerchicov-bp
Copy link

gerchicov-bp commented Apr 12, 2018

@adreif where is index declaration?

The second problem which allows to use this code as the example only and requires significant changes is:
extension ViewController: UIPageViewControllerDataSource {
You write an extension over all view controllers even those ones where you have never needed page view controller

@ckalbas
Copy link

ckalbas commented Apr 27, 2018

@gerchicov-bp Actually, he's extending the custom class ViewController, not UIViewController

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment