42

I am using Xcode 6 and implementing UIPageViewController for my app. I followed appcoda's tutorial, and everything works except the page indicators. This is because I cannot set the transition style of UIPageViewController to scroll.

Graphically, when I click on the PageViewController, the tab shows View Controller instead of Page View Controller like appcoda (See its image below)

enter image description here

This is what mine looks like:

enter image description here

And yes, my custom class is set to: UIPageViewController as it is in the tutorial. enter image description here

Programmatically, I try to set the transition style with:

    self.pageViewController.transitionStyle = UIPageViewControllerTransitionStyle.Scroll

but it fails to build, telling me that it Could not find member transition style. One last weird thing I would like to point out is that if I just write self.pageViewController.transitionStyle, it builds successfully, but it still uses the Page Curl Transition.

Could anyone help me? I am using Swift, Xcode 6, and developing on the iOS 8 SDK.

Neeku
  • 3,646
  • 8
  • 33
  • 43
sameetandpotatoes
  • 1,220
  • 3
  • 17
  • 35

16 Answers16

43

The issue is that when you create a UIPageViewController inside a Container, the container is first created with a UIViewController, and that s the controller you see your options for.

In order to fix it you have to delete UIViewController where you set your custom UIPageViewController. Then drag UIPageViewController from the controls picker and hook up the embed segue from the container to that controller, then you can set your custom pager controller as well as set transition to scroll.

halfer
  • 19,824
  • 17
  • 99
  • 186
Marcin D
  • 918
  • 7
  • 14
42

You're getting an error because transitionStyle is a readonly property. If you want to set the transition style of the page controller programmatically, it can only be done during initialization with the method:

init(transitionStyle style: UIPageViewControllerTransitionStyle, navigationOrientation navigationOrientation: UIPageViewControllerNavigationOrientation, options options: [NSObject : AnyObject]!) { ... }

More info in the documentation.

Mick MacCallum
  • 129,200
  • 40
  • 280
  • 281
  • This seems like it would work, but I am having trouble implementing it. Where exactly would I put this? In appcoda's tutorial, I instantiate the UIPageViewController in my ViewController with: `self.pageViewController = self.storyboard.instantiateViewControllerWithIdentifier("PageViewController") as UIPageViewController`. (Sorry about these basic questions, I am learning Swift and Objective C and iOS development in general at the same time) – sameetandpotatoes Jul 04 '14 at 16:16
  • @sameetandpotatoes That's alright; and if you're creating your page view controller in storyboard, you don't actually have to call this method yourself. If you were creating your page view controller completely programmatically, you would use this initializer, but since you're using storyboard, just select the transition style the way you're already doing it. – Mick MacCallum Jul 05 '14 at 13:40
  • but that's the source of my problem. I am doing it in storyboard, but when I go to select the transition style, there is no option for Scroll because Xcode thinks its a View Controller and not a Page View Controller. – sameetandpotatoes Jul 05 '14 at 13:59
  • 7
    There is specifically a UIPageViewController icon in Interface Builder. Are you using this as opposed to dragging out a UIViewController and changing it's custom class to UIPageViewController? – rvijay007 Jul 11 '14 at 05:50
  • 1
    That was my issue: I embedded one in a container. I had to delete the autogenerated VC and segue, and recreate them using the proper object. You can't just change the class type. Which is lame. – i_am_jorf Jan 06 '15 at 01:45
  • @jeffamaphone I have the same problem: It's embedded in a container and I don't have any point where I can change the transition style – Claus Mar 01 '15 at 20:07
  • 1
    If you embed it in IB as a `UIPageViewController` there should be an option to change the transition style. If you took a `UIViewController` which was already embedded and just set the custom class, the option won't be there. Delete what you have, drag out the proper class from the object selector, and re-wire the embed segue. – i_am_jorf Mar 01 '15 at 20:22
31

Swift 3.0

required init?(coder aDecoder: NSCoder) {
    super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
}
Cilvet
  • 470
  • 6
  • 10
  • 2
    I don't feed comfortable doing this... aren't we triggering the end of the world not calling the init(coder:) initializer? – Nuno Gonçalves Mar 10 '17 at 12:14
  • Thank you It works for swift 5.0 too. This solution works to whom use the UIPageViewController in a nib file or the .storyboard – Amjad Tubasi Sep 14 '19 at 17:16
17

in ios 8 swift3

override init(transitionStyle style: UIPageViewControllerTransitionStyle, navigationOrientation: UIPageViewControllerNavigationOrientation, options: [String : Any]? = nil) {
        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: options)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
Divyesh Gondaliya
  • 884
  • 11
  • 21
11

This is how I solved this problem in Swift 2.0

1. Created a class which is subclass of class UIPageViewController

    import UIKit
    
    class OPageViewController: UIPageViewController {
        
        override init(transitionStyle style: UIPageViewControllerTransitionStyle, navigationOrientation: UIPageViewControllerNavigationOrientation, options: [String : AnyObject]?) {

           // Here i changed the transition style: UIPageViewControllerTransitionStyle.Scroll           
            super.init(transitionStyle: UIPageViewControllerTransitionStyle.Scroll, navigationOrientation: UIPageViewControllerNavigationOrientation.Horizontal, options: options)
        }
    
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
    
    }

2.Than i just used it :D

pageController = OPageViewController()
pageController.dataSource = self
pageController.setViewControllers(NSArray(object: vc) as? [UIViewController], direction: .Forward, animated: true, completion: nil)
pageController.view.frame = CGRectMake(0, container.frame.origin.y, view.frame.size.width, container.frame.size.height);
Dardan
  • 531
  • 7
  • 15
10

I know this a little bit late, but I just had the same problem and realized that it was originated because I was using a simple UIViewController, even when my custom view controller class inherits from an UIPageViewController, aparently the graphic menu of xcode doesn't recognize it.

The solution was to delete in story board the view controller and drag a PageViewController to replace it. This will have the graphic menu with the scroll option.

Necreaux
  • 9,451
  • 7
  • 26
  • 43
Jorge Barboza
  • 151
  • 2
  • 5
10

Xcode 7.1 & Swift 2

All other solutions did not fully work for me at the latest Swift, especially since my class also inherits from UIPageViewControllerDataSource and UIPageViewControllerDelegate.

To set the PageViewController transition to .Scroll just add these 2 methods to your class:

override init(transitionStyle style: UIPageViewControllerTransitionStyle, navigationOrientation: UIPageViewControllerNavigationOrientation, options: [String : AnyObject]?) {
    super.init(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: options)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}
Sebastian
  • 8,952
  • 3
  • 32
  • 30
10

Swift 5 & 4: Just put this 2 functions before viewDidLoad() in your pageview VC

override init(transitionStyle style: UIPageViewController.TransitionStyle, navigationOrientation: UIPageViewController.NavigationOrientation, options: [UIPageViewController.OptionsKey : Any]? = nil) {
    super.init(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil)
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
evevF
  • 131
  • 2
  • 5
8

Easiest way to do this programmatically in Swift 2.0 (without subclassing):

class PageViewController: UIPageViewController {

     override init(transitionStyle style: UIPageViewControllerTransitionStyle, navigationOrientation navigationOrientation: UIPageViewControllerNavigationOrientation, options options: [NSObject : AnyObject]!) {
          super.init(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: options) 
     }

}
PL175
  • 81
  • 1
  • 2
5

This worked for me . Because if I override init for transitionStyle , it never gets called if you have set pageViewController in a container view in Storyboard.

required init?(coder aDecoder: NSCoder) {

        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
    }
Shirish
  • 295
  • 3
  • 19
4

Swift 4 programmatically set the transition style of UIPageViewController

This is straight from 'UIPageViewController.h' line 61-97

Just put this before viewDidLoad() in your UIPageViewController() class

    override init(transitionStyle style: 
UIPageViewControllerTransitionStyle, navigationOrientation: UIPageViewControllerNavigationOrientation, options: [String : Any]? = nil) {
            super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
        }
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
A. Welch
  • 356
  • 1
  • 3
  • 8
2

Swift 5

class OnboardingController: UIPageViewController {

    override init(transitionStyle style: UIPageViewController.TransitionStyle, navigationOrientation: UIPageViewController.NavigationOrientation, options: [UIPageViewController.OptionsKey : Any]? = nil) {
        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
    }

    required init?(coder: NSCoder) {
        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
Fattie
  • 27,874
  • 70
  • 431
  • 719
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
  • 1
    Lance, in your excellent code, there's no reason you wouldn't also set it in the STORYBOARD call. (Note that these days, bizarrely, you CAN NOT set simply "scroll" in storyboard - for some reason they removed it from IB. You must set it in code as per your code.) I added it to your answer, of course edit as you wish cheers – Fattie Apr 03 '23 at 23:33
  • @Fattie Thanks for the edit! Honestly I haven’t used Storyboard in years. I do everything programmatically so it’s better that you updated my answer so that it helps the next person who does you Storyboard. Cheers!!! – Lance Samaria Apr 05 '23 at 00:42
  • heh right on Lance! cheers ! – Fattie Apr 05 '23 at 22:26
1

This is a known bug with UIPageViewController

You can read an explanation of the cause in this SO question and more comprehensively in this one.

I used the AppCoda Tutorial as well to get a handle on PageViewControllers. Another SO user actually wrote a gist that solved the problem for me in a way that I didn't have to change a line of code in my own project. Just drop AVC in to your project and call that instead of UIPageViewController in your code.

Paul de Lange's AlzheimerViewController.

Community
  • 1
  • 1
Sean Dev
  • 1,239
  • 1
  • 17
  • 31
1

In swift 5

In the Page view Controller you can write following code

TransitionStyle scroll

    required init?(coder aDecoder: NSCoder) {
        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
    }

For transitionStyle curl

 required init?(coder aDecoder: NSCoder) {
        super.init(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil)
    }

Thank You

M Murteza
  • 1,629
  • 15
  • 10
0

swift 3 xcode 8 in

class ...: UIPageViewController {

override var transitionStyle: UIPageViewControllerTransitionStyle {
    return .scroll
}

override var navigationOrientation: UIPageViewControllerNavigationOrientation {
    return .horizontal
}

}

Anton Russia
  • 197
  • 1
  • 2
0

None of the solutions below worked for Swift 5. here is what worked for me, in my case i needed the view controller to be presented on top of the other view controller with low opacity background:

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nil, bundle: nil)

    self.setupView()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    self.setupView()
}

private func setupView() {
    self.modalTransitionStyle = .crossDissolve
    self.modalPresentationStyle = .overCurrentContext
    self.view.backgroundColor = UIColor.red.withAlphaComponent(0.3)
}
Shahriyar
  • 520
  • 7
  • 18