Change pages with UIPageViewController using buttons in my View Controllers swift 4 - ios

I have a UIPageViewController that let's me navigate between multiple view controller.
My app works swiping my screen, but I want to remove the swipe gesture to navigate between the pages for different buttons inside my views
This is the code that I'm using on with my page view cxontroller
class RootPageViewController: UIPageViewController,UIPageViewControllerDataSource {
lazy var viewControllerList: [UIViewController] = {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let VC1 = storyBoard.instantiateViewController(withIdentifier: "orangeVC")
let VC2 = storyBoard.instantiateViewController(withIdentifier: "blueVC")
let VC3 = storyBoard.instantiateViewController(withIdentifier: "purpleVC")
return [VC1, VC2, VC3]
}()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
if let firstViewController = viewControllerList.first {
self.setViewControllers([firstViewController], direction: .forward, animated: true, completion: nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let vcIndex = viewControllerList.index(of: viewController) else {return nil}
let previousIndex = vcIndex-1
guard previousIndex >= 0 else {return nil}
guard viewControllerList.count > previousIndex else {return nil}
return viewControllerList[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let vcIndex = viewControllerList.index(of: viewController) else {return nil}
let nextIndex = vcIndex+1
guard viewControllerList.count != nextIndex else {return nil}
guard viewControllerList.count > nextIndex else {return nil}
return viewControllerList[nextIndex]
}
}

You only need this line inside the button action
self.setViewControllers([viewControllerList[indexHere]], direction: .forward, animated:false, completion: nil)

Related

Swift - PageViewController drag animation

I'm currently trying to implement a PageViewController just like in the example below (I assume they're using one as well).
My code is set up, but I'm still struggling to get the animation right: to be exact that (just like in the example) when you swipe the main view away, it seems the view on the left was underneath the main the whole time. How do they still display a little from the main ViewController?
Additionally I've recognized that swiping seems a lot more abrupt than in my app, as if there were magnets on the edge.
Do I have to work with constraints or does it take coding?
Is it even a PageViewController or solely a subview inside of a view?
My code in case it's needed:
import UIKit
import Firebase
class RootPageViewController: UIPageViewController, UIPageViewControllerDataSource {
lazy var viewControllerList:[UIViewController] = {
let sb = UIStoryboard(name: "Main", bundle: nil)
let vc1 = sb.instantiateViewController(withIdentifier: "timelineView")
let vc2 = sb.instantiateViewController(withIdentifier: "mainView")
return [vc1, vc2]
}()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
if let secondViewController = viewControllerList[1] as? MainViewController {
self.setViewControllers([secondViewController], direction: .forward, animated: true, completion: nil)
secondViewController.buttonAdd.action = #selector(addData(_:))
secondViewController.buttonReminder.addTarget(self, action: #selector(goToReminder(_:)), for: .touchUpInside)
secondViewController.buttonSettings.addTarget(self, action: #selector(goToSettings(_:)), for: .touchUpInside)
secondViewController.buttonUser.addTarget(self, action: #selector(goToProfile(_:)), for: .touchUpInside)
}
}
#objc func addData(_ sender: Any) {
performSegue(withIdentifier: "goToAdd", sender: self)
}
#objc func goToReminder(_ sender: Any) {
performSegue(withIdentifier: "goToNotifications", sender: self)
}
#objc func goToSettings(_ sender: Any) {
performSegue(withIdentifier: "goToSettings", sender: self)
}
#objc func goToProfile(_ sender: Any) {
if let user = Auth.auth().currentUser {
self.performSegue(withIdentifier: "goToEdit", sender: self)
} else {
performSegue(withIdentifier: "goToProfile", sender: self)
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let vcIndex = viewControllerList.firstIndex(of: viewController) else { return nil }
let previousIndex = vcIndex - 1
guard previousIndex >= 0 else { return nil }
guard viewControllerList.count > previousIndex else { return nil }
return viewControllerList[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let vcIndex = viewControllerList.firstIndex(of: viewController) else { return nil }
let nextIndex = vcIndex + 1
guard viewControllerList.count != nextIndex else { return nil }
guard viewControllerList.count > nextIndex else { return nil }
return viewControllerList[nextIndex]
}
}

Is it possible to segue to a UIPageViewController?

I am attempting to add a tutorial section to my application after the user logs in. When the app loads up, they will first come to a login screen and enter their credentials. Once they are verified, I want to segue to a UIPageViewController and show them two pages of instructions on how to use the application. However, all of my attempts at doing so have resulted in a black screen. Here is my current attempt:
import UIKit
class TutorialPageViewController: UIPageViewController {
var pages: [UIViewController] = []
override func viewDidLoad()
{
super.viewDidLoad()
self.dataSource = self
self.delegate = self
print("LOADING")
let firstView = storyboard?.instantiateViewController(withIdentifier: "TutorialPage1") as! TutorialPage1ViewController
let secondView = storyboard?.instantiateViewController(withIdentifier: "TutorialPage2") as! TutorialPage2ViewController
pages = [firstView, secondView]
let startingViewController = self.pages[0]
let viewControllers: [UIViewController] = [startingViewController]
self.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: {(done: Bool) in})
}
func viewControllerAtIndex(index:NSInteger) -> UIViewController {
return pages[index]
}
}
extension TutorialPageViewController: UIPageViewControllerDataSource
{
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = pages.index(of: viewController) else { return nil }
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else { return pages.last }
guard pages.count > previousIndex else { return nil }
return pages[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
{
guard let viewControllerIndex = pages.index(of: viewController) else { return nil }
let nextIndex = viewControllerIndex + 1
guard nextIndex < pages.count else { return pages.first }
guard pages.count > nextIndex else { return nil }
return pages[nextIndex]
}
}
extension TutorialPageViewController: UIPageViewControllerDelegate { }
The print statement in my viewDidLoad method is not being called, so I don't understand what I am doing wrong. I have created a push segue to TutorialPageViewController from the login view controller, but nothing ever loads.
Any help is appreciated.
Try checking the sample Project at Below GitHub Repo :
Link - https://github.com/RockinGarg/Stack_PageVC.git
Contains two Different Ways to Access
1. Making use of Container View and PageVC as SubView
2. Using Segue

How do I hide the status bar on my UIPageViewController? (All view controllers)

I've searched every question/answer I can find on here, but I can't figure out how to hide the status bar for all of the view controllers in my UIPageViewController. Here's the code from my UIPageViewController class:
class TipsVC: UIPageViewController, UIPageViewControllerDelegate {
lazy var VCArr: [UIViewController] = {
return [self.VCInstance(name: "T1"),
self.VCInstance(name: "T2"),
self.VCInstance(name: "T3")]
}()
private func VCInstance(name: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: name)
}
override public func viewDidLoad() {
super.viewDidLoad()
//self.dataSource = self
self.delegate = self
if let OB1 = VCArr.first {
setViewControllers([OB1], direction: .forward, animated: true, completion: nil)
let pageController = UIPageControl.appearance()
pageController.pageIndicatorTintColor = UIColor(red:1.00, green:0.88, blue:0.92, alpha:1.0)
pageController.currentPageIndicatorTintColor = UIColor(red:1.00, green:0.25, blue:0.51, alpha:1.0)
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for view in self.view.subviews {
if view is UIScrollView {
view.frame = UIScreen.main.bounds
} else if view is UIPageControl {
view.backgroundColor = UIColor.clear
}
}
}
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?{
guard let viewControllerIndex = VCArr.index(of: viewController) else {
return nil
}
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else {
return VCArr.last
}
guard VCArr.count > previousIndex else {
return nil
}
return VCArr[previousIndex]
}
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?{
guard let viewControllerIndex = VCArr.index(of: viewController) else {
return nil
}
let nextIndex = viewControllerIndex + 1
guard nextIndex < VCArr.count else {
return VCArr.first
}
guard VCArr.count > nextIndex else {
return nil
}
return VCArr[nextIndex]
}
public func presentationCount(for pageViewController: UIPageViewController) -> Int{
return VCArr.count
}
public func presentationIndex(for pageViewController: UIPageViewController) -> Int{
guard let OB1 = viewControllers?.first,
let OB1Index = VCArr.index(of: OB1) else {
return 0
}
return OB1Index
}
public func nextPageWithIndex(index: Int)
{
let nextVC = VCArr[index]
setViewControllers([nextVC], direction: .forward, animated: true, completion: nil)
}
}
and here's a code sample from one of my viewControllers:
class T1: UIViewController {
#IBOutlet var nextBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
UIApplication.shared.isStatusBarHidden = true
}
#IBAction func nextBtnDidPress(_ sender: Any) {
let next = self.parent as! TipsVC
next.nextPageWithIndex(index: 1)
}
}
I'm well aware of how to hide the status bar on regular view controllers, but I'm unable to get the same results when I'm using a UIPageViewController. What's going on?
To hide statusbar from particluar viewController you need to hide status bar in viewWillAppear and hide status bar in viewWillDisAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIApplication.shared.isStatusBarHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
UIApplication.shared.isStatusBarHidden = false
}
viewWillAppear will call before opening particular viewController and viewWillDisAppear call after dismiss particular viewController
if you face problem with UIPageViewController use UIViewController and embed UIPageViewController inside that for reference check below code
var pageContainer: UIPageViewController!
pageContainer = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
pageContainer.delegate = self
pageContainer.dataSource = self
pageContainer.setViewControllers([getViewControllerAtIndex(index: 0)] as [UIViewController], direction: .forward, animated: false, completion: nil)
pageContainer.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.view.addSubview(pageContainer.view)
Hope this will help you

Change specific page UiPageViewController

I have a Page view controller (see below), what i want to achieve is to go to the FirstVC from ThirdVC and only from that!! with a function or a button, can anyone help me?
Here you can see the code of my PageVC
import UIKit
class PageVC: UIPageViewController,UIPageViewControllerDataSource, UIPageViewControllerDelegate{
lazy var VCArr: [UIViewController] = {
return [self.VCInstance(name: "FirstVC"), self.VCInstance(name: "SecondVC"), self.VCInstance(name: "ThirdVC")]
}()
private func VCInstance(name: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle:nil).instantiateViewController(withIdentifier: name)
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
if let firstVC = VCArr.first {
setViewControllers([firstVC], direction: .forward, animated: true, completion: nil)
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for view in self.view.subviews {
if view is UIScrollView {
view.frame = UIScreen.main.bounds
} else if view is UIPageControl {
view.backgroundColor = UIColor.clear
}
}
}
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = VCArr.index(of: viewController) else {
return nil
}
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else{
return VCArr.last
}
guard VCArr.count > previousIndex else {
return nil
}
return VCArr[previousIndex]
}
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = VCArr.index(of: viewController) else {
return nil
}
let nextIndex = viewControllerIndex + 1
guard nextIndex < VCArr.count else{
return VCArr.first
}
guard VCArr.count > nextIndex else {
return nil
}
return VCArr[nextIndex]
}
public func presentationCount(for pageViewController: UIPageViewController) -> Int {
return VCArr.count
}
public func presentationIndex(for pageViewController: UIPageViewController) -> Int {
guard let firstViewController = viewControllers?.first, let firstViewControllerIndex = VCArr.index(of: firstViewController) else{
return 0
}
return firstViewControllerIndex
}
}
Ok i found a solution here:
How do I change the UIPageViewController from WITHIN one of the UIViewControllers that is part of the UIPageViewController?
Simply i added this function to PageVC:
func nextPageWithIndex(index: Int)
{
let nextWalkthroughVC = VCArr[index]
setViewControllers([nextWalkthroughVC], direction: .forward, animated: true, completion: nil)
}
Then in the ThirdVC view controller i added in my function:
let parent = self.parent as! PageVC
parent.nextPageWithIndex(index: 0)
Where 0 is the index of the view controller that i want to show
And works perfectly!

UITableView in UIPageViewController in NavigationController with Page Control

I have the following set up:
UINavigationController -> UIPageViewController-> UITableViewController/UIViewController/UIViewController
my UIPageViewController looks like this:
import UIKit
class DailyRoutinePageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var pages = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
self.automaticallyAdjustsScrollViewInsets = false;
self.delegate = self
self.dataSource = self
self.navigationItem.title = getActiveUserName()
let page1: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("dailyRoutinePage1")
let page2: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("dailyRoutinePage2")
let page3: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("dailyRoutinePage3")
pages.append(page1)
pages.append(page2)
pages.append(page3)
setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
#IBAction func buttonKontakte(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("careTaker")
self.presentViewController(vc, animated: true, completion: nil)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.indexOf(viewController)!
let previousIndex = abs((currentIndex - 1) % pages.count)
return pages[previousIndex]
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let currentIndex = pages.indexOf(viewController)!
let nextIndex = abs((currentIndex + 1) % pages.count)
return pages[nextIndex]
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return pages.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
}
this works fine. I can scroll through all pages. Now I want to add a Page Control. I can add a Page Control to the UIPageView's. But how can I add one to the UITableViewController? And when I scroll through the pages the Page Control scroll with the pages. How can I make it stand still?
An other problem: The PageViewController doesn't respect the navigation title bar. So there is content behind the Naviagtion bar at the top. How can I fix this?

Resources