Adjust containerView Height based on PageviewController - ios

I'm kinda having a trouble adjusting the ContainerView height based on the height of the pageViewController.
So on this example I have two pages : "Yellow Page","Purple Page"
Yellow page = 120px Height
Purple page = 250px Height
All I wanna work out is to adjust the height automatically as I scroll on the pageViewController embedded on the containerView.
Hope you can help, thank you!
Here's the Image.
Storyboard Image
This is my PageViewController Code.
import UIKit
class PageViewController: UIPageViewController,UIPageViewControllerDataSource, UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
let previousIndex = abs((currentIndex - 1) % pages.count)
return pages[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
let nextIndex = abs((currentIndex + 1) % pages.count)
return pages[nextIndex]
}
var pages = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.dataSource = self
let page1: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "page1");
let page2: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "page2");
pages.append(page1)
pages.append(page2)
setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return pages.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
override func viewDidLayoutSubviews() {
}
}

You can hook the height of the container and controls it from the pager like this
#IBOutlet weak var conH: NSLayoutConstraint!
//
func callMe(value:CGFloat) {
conH.constant = value
self.view.layoutIfNeeded()
}
//
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
let vc = UIApplication.shared.keyWindow?.rootViewController as! ViewController
let currentIndex = pages.index(of: previousViewControllers.first!)!
let nextIndex = abs((currentIndex + 1) % pages.count)
vc.callMe(value:nextIndex == 0 ? 100 : 200)
}
//

Related

PageViewController - Auto Slide - Swift 3

I am trying to auto-slide the page view controller pages and the page indicator simultaneously. There are 5 pages in my page view controller. The flow works fine from pic 1-5, but I am unable to go back from 5th to 1st image and restart the auto sliding.
Below is my code:
import UIKit
class PageSliderViewController: UIViewController , UIPageViewControllerDataSource, UIPageViewControllerDelegate {
#IBOutlet weak var pageControl: UIPageControl!
var pageContainer: UIPageViewController!
// The pages it contains
var pages = [UIViewController]()
// Track the current index
var currentIndex: Int?
private var pendingIndex: Int?
override func viewDidLoad() {
super.viewDidLoad()
// Setup the pages
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let page1: UIViewController! = storyboard.instantiateViewController(withIdentifier: "Page1")
let page2: UIViewController! = storyboard.instantiateViewController(withIdentifier: "Page2")
let page3: UIViewController! = storyboard.instantiateViewController(withIdentifier: "Page3")
let page4: UIViewController! = storyboard.instantiateViewController(withIdentifier: "Page4")
let page5: UIViewController! = storyboard.instantiateViewController(withIdentifier: "Page5")
pages.append(page1)
pages.append(page2)
pages.append(page3)
pages.append(page4)
pages.append(page5)
// Create the page container
pageContainer = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
pageContainer.delegate = self
pageContainer.dataSource = self
pageContainer.setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
currentIndex = 0
// Add it to the view
view.addSubview(pageContainer.view)
// Configure our custom pageControl
self.view.bringSubview(toFront: self.loginButton)
self.view.bringSubview(toFront: self.signUpButton)
self.view.bringSubview(toFront: self.pageControl)
pageControl.numberOfPages = pages.count
pageControl.currentPage = 0
Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(self.next(_:)),
userInfo: nil,
repeats: true)
}
func next(_ timer: Timer) {
pageContainer.goToNextPage()
currentIndex = currentIndex! + 1
if currentIndex == pageControl.numberOfPages{
currentIndex = 0
}
pageControl.currentPage = currentIndex!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - UIPageViewController delegates
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
if currentIndex == 0 {
return nil
}
let previousIndex = abs((currentIndex - 1) % pages.count)
return pages[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
if currentIndex == pages.count-1 {
return nil
}
let nextIndex = abs((currentIndex + 1) % pages.count)
return pages[nextIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
pendingIndex = pages.index(of: pendingViewControllers.first!)
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed {
currentIndex = pendingIndex
if let index = currentIndex {
pageControl.currentPage = index
}
}
}
}
extension UIPageViewController {
func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) {
if let currentViewController = viewControllers?[0] {
if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) {
setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion)
}
}
}
}
Note that through this code the page control goes from 5th to 1st dot but the page is not changing. There is some minor mistake but unable to figure it out. Any help would be greatly appreciated!
I haven't tried to run this code, but my guess is:
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
if currentIndex == pages.count-1 {
return nil
}
let nextIndex = abs((currentIndex + 1) % pages.count)
return pages[nextIndex]
}
Arrays are zero-based, so if you are currently looking at page5, you are looking at pages[4] ... and pages.count - 1 equals 4. So, your code is saying:
if the current page is page5
return nil
So your func goToNextPage() extension calls for viewControllerAfter and gets nil in return.
You most likely want to change viewControllerAfter to be:
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
// you don't need this, because you are using % modulo operator
// to keep "nextIndex" within the array bounds
//if currentIndex == pages.count-1 {
// return nil
//}
let nextIndex = abs((currentIndex + 1) % pages.count)
return pages[nextIndex]
}

transition page with uipageviewcontroller

I have a view container containing a UIPageViewController. to him they are associated with 2 viewController of UIImageView. It works almost everything. I can not change the animations to scroll through images. the animation is always that of the page curl while I would like a simple scroll. how to do?
class MyPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var pages = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.dataSource = self
let page1: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "page1")
let page2: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "page2")
pages.append(page1)
pages.append(page2)
setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
let previousIndex = abs((currentIndex - 1) % pages.count)
return pages[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
let nextIndex = abs((currentIndex + 1) % pages.count)
return pages[nextIndex]
}
private func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return pages.count
}
private func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
}
How are you initiating the UIPageViewController?
From code, you can specify a transitionStyle in the constructor, as seen here
From storyboard, you can specify the same transitionStyle in the storyboard itself, as shown in this SO answer

UIPageViewContoller in container view with page control icon

I am writing a Swift app with three views. I have achieved this by putting a UIPageViewController inside a container and having that switch when you swipe, from another Stack Overflow article: UIPageViewController and storyboard. I would also like to have dots on the bottom indicating the page you are on. But, the UIPageControl I am using can only be placed on the view controller with the container, and the code with the current page is in the page controller's code. Here is my code:
class ContainerView : UIViewController {
#IBOutlet var myPageController: UIPageControl!
}
class MyPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var pages = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.dataSource = self
let page1: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "Page1ID")
let page2: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "Page2ID")
let page3: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "Page3ID")
pages.append(page1)
pages.append(page2)
pages.append(page3)
setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
if (currentIndex == 0) {
return pages[currentIndex]
}
let previousIndex = abs((currentIndex - 1) % pages.count)
//myPageControl.currentPage = previousIndex
return pages[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.index(of: viewController)!
if (currentIndex == 2) {
return pages[currentIndex]
}
let nextIndex = abs((currentIndex + 1) % pages.count)
//myPageControl.currentPage = nextIndex
return pages[nextIndex]
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return pages.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
}
How could I access the parent view controller (ContainerView) from the child in the container (MyPageViewController)? I'm new to Swift/Objective-C but have programmed in other languages (C++, Python). If you need the storyboard, please ask.

UIPageControl to show current page

I made a PageViewController to switch between different View Controllers, and i'd like to show which page we see. I added a pageControl, and gave it the following code.
pageControl.currentPageIndicatorTintColor = UIColor.blueColor()
pageControl.pageIndicatorTintColor = UIColor.lightGrayColor()
pageControl.numberOfPages = pages.count
The complete code:
import UIKit
class ViewControllerSportinfrastructuur: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
#IBOutlet weak var pageControl: UIPageControl!
var pageViewController: UIPageViewController!
let pages = ["PageOneViewController", "PageTwoViewController"]
//MARK: - page view controller data source
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
if let index = pages.indexOf(viewController.restorationIdentifier!) {
if index > 0 {
return viewControllerAtIndex(index - 1)
}
}
return nil
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
if let index = pages.indexOf(viewController.restorationIdentifier!) {
if index < pages.count - 1 {
return viewControllerAtIndex(index + 1)
}
}
return nil
}
func viewControllerAtIndex(index: Int) -> UIViewController? {
let vc = storyboard?.instantiateViewControllerWithIdentifier(pages[index])
return vc
}
override func viewDidLoad() {
super.viewDidLoad()
if let vc = storyboard?.instantiateViewControllerWithIdentifier("MyPageViewController") {
self.addChildViewController(vc)
self.view.addSubview(vc.view)
pageViewController = vc as! UIPageViewController
pageViewController.dataSource = self
pageViewController.delegate = self
pageViewController.setViewControllers([viewControllerAtIndex(0)!], direction: .Forward, animated: true, completion: nil)
pageViewController.didMoveToParentViewController(self)
pageControl.currentPageIndicatorTintColor = UIColor.blueColor()
pageControl.pageIndicatorTintColor = UIColor.lightGrayColor()
pageControl.numberOfPages = pages.count
}
}
Does anyone know what code i should use to set up the current page? Thanks in advance!
EDIT: found the answer already!
I added pageControl.currentPage = index in following functions:
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
if let index = pages.indexOf(viewController.restorationIdentifier!) {
pageControl.currentPage = index
if index > 0 {
return viewControllerAtIndex(index - 1)
}
}
return nil
}
And did the same for the viewControllerAfterViewController func!
The UIPageViewController provides a default UIPageControl - I would recommend to make use of it if you don't have particular custom requirements.
In order to show it you need to implement the following two optional methods in your UIPageViewControllerDataSource:
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return n //number of view controllers
}
func presentationIndex(for pageViewController: UIPageViewController) -> Int {
return i //index of the visible view controller
}
Set pageViewController.delegate = self, implement protocol UIPageViewControllerDelegate
and use on of these methods to set self.pageControl.currentPage = ...
optional func pageViewController(_ pageViewController: UIPageViewController,
willTransitionToViewControllers pendingViewControllers: [UIViewController])
optional func pageViewController(_ pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers previousViewControllers: [UIViewController],
transitionCompleted completed: Bool)

How to implement a vertical UIPageViewController inside a horizontal UIPageViewController

I want to adjust my UIPageViewController to work like in the image, currently 1b is able to go 2a etc. What do i need to do to lock the direction like in the image? Did i forget anything or am i using the wrong logic. Any tip would help a lot!
Note the vertical UIPageViewController is inside the horizontal UIPageViewController
Horizontal UIPageViewController code
class MyPageViewController: UIPageViewController , UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var pages = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.dataSource = self
let page1: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("page1")
let page2: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("page2")
let page3: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("page3")
pages.append(page1)
pages.append(page2)
pages.append(page3)
setViewControllers([page2], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.indexOf(viewController)!
let previousIndex = abs((currentIndex - 1) % pages.count)
if (previousIndex > 0)
{
return nil
}
return pages[previousIndex]
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.indexOf(viewController)!
let nextIndex = abs((currentIndex + 1) % pages.count)
if (nextIndex < 1)
{
return nil
}
return pages[nextIndex]
}
Vertical UIPageViewController code
class upAndDownViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var pages = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.dataSource = self
let midPage: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("midPage")
let topPage: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("topPage")
pages.append(midPage)
pages.append(topPage)
setViewControllers([midPage], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.indexOf(viewController)!
let nextIndex = abs((currentIndex + 1) % pages.count)
if (nextIndex < 1)
{
return nil
}
return pages[nextIndex]
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.indexOf(viewController)!
let previousIndex = abs((currentIndex - 1) % pages.count)
if (previousIndex > 0)
{
return nil
}
return pages[previousIndex]
}
I put the horizontal UIPageViewController inside the vertical UIPageViewController. That fixed it but for some reasons other ViewControllers opened inside the TOP vertical UIPageViewController are able to Page down, i will look more into that and probably fix it.

Resources