Swift - Bringing UIPageViewController controls to front - swift

I'm having some trouble bringing the dotted UIPageControls to the front after I filled out the whole screen.
Here's my current code:
import UIKit
class ViewController: UIViewController, UIPageViewControllerDataSource {
//This outlet wasn't originally there. Added a UIPageControl as an attempt to solve my issue
#IBOutlet var pageControl: UIPageControl!
var pageViewController : UIPageViewController?
var pageTitles : Array<String> = ["Orc", "Elven", "Undead"]
var pageImages : Array<String> = ["Plain_Orc.png", "Plain_Elf.png", "Plain_Undead.png"]
var currentIndex : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.pageViewController = UIPageViewController(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: nil)
self.pageViewController!.dataSource = self
let startingViewController: PageContentViewController = self.viewControllerAtIndex(0)!
let viewControllers: NSArray = [startingViewController]
self.pageViewController!.setViewControllers(viewControllers, direction: .Forward, animated: false, completion: nil)
self.pageViewController!.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height + 37);
self.addChildViewController(self.pageViewController!)
//self.view.addSubview(self.pageViewController!.view)
//replacing addSubview from insane-36
self.view.insertSubview(pageViewController!.view, belowSubview: self.pageControl!)
self.pageViewController!.didMoveToParentViewController(self)
//Bring pagecontrols to front? (DOsESN'T WORK)
//self.view.bringSubviewToFront(self.pageViewController!.view)
//attempt to fix above code from insane-36
view.bringSubviewToFront(self.pageControl!)
view.sendSubviewToBack(self.pageViewController!.view)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
{
var index = (viewController as PageContentViewController).pageIndex
if (index == 0) || (index == NSNotFound) {
return nil
}
index--
println("Decreasing Index: \(String(index))")
return self.viewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController?
{
var index = (viewController as PageContentViewController).pageIndex
if index == NSNotFound {
return nil
}
index++
println("Increasing Index: \(String(index))")
if (index == self.pageTitles.count) {
return nil
}
return self.viewControllerAtIndex(index)
}
func viewControllerAtIndex(index: Int) -> PageContentViewController?
{
if self.pageTitles.count == 0 || index >= self.pageTitles.count
{
return nil
}
// Create a new view controller and pass suitable data.
let pageContentViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageContentViewController") as PageContentViewController
pageContentViewController.imageFile = self.pageImages[index]
pageContentViewController.titleText = self.pageTitles[index]
pageContentViewController.pageIndex = index
self.currentIndex = index
return pageContentViewController
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int
{
return self.pageTitles.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int
{
return 0
}
}
I thought the line that brings the pageViewController view to front would fix my issue, but it doesn't work. Hopefully someone can give me a push in the right direction :)

Use any one of the following method to send the UIPageViewController's view to the back of the UIPageControl,
Instead of using addSubview: to add UIPageViewController's
view, use
view.insertSubview(pageViewController.view, belowSubview:self.pageControl)
Use bringSubviewToFront: method,
view.bringSubviewToFront(self.pageControl) // after you have added the UIPageViewController's view
Use sendSubviewToBack: method,
view.sendSubviewToBack(self.pageViewController.view)

Related

How to stop after view scroll in page controller at particular view

I integrated pageviewcontroller using storyboard. i have 4 view. how to stop after scroll at third view. how to disable after scoll?
This my code. how to stop after scroll in ThirdViewController.
import UIKit
class PageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
var pageControl = UIPageControl()
// MARK: UIPageViewControllerDataSource
lazy var orderedViewControllers: [UIViewController] = {
return [self.newVc(viewController: "sbRed"),self.newVc(viewController: "sbBlue"),self.newVc(viewController: "sbOrange"),self.newVc(viewController: "sbGray")]
}()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
// This sets up the first view that will show up on our page control
if let firstViewController = orderedViewControllers.first {
setViewControllers([firstViewController],
direction: .forward,
animated: true,
completion: nil)
}
configurePageControl()
// Do any additional setup after loading the view.
}
func configurePageControl() {
// The total number of pages that are available is based on how many available colors we have.
pageControl = UIPageControl(frame: CGRect(x: 0,y: UIScreen.main.bounds.maxY - 50,width: UIScreen.main.bounds.width,height: 50))
self.pageControl.numberOfPages = orderedViewControllers.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.black
self.pageControl.pageIndicatorTintColor = UIColor.white
self.pageControl.currentPageIndicatorTintColor = UIColor.black
self.view.addSubview(pageControl)
}
func newVc(viewController: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: viewController)
}
// MARK: Delegate methords
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
let pageContentViewController = pageViewController.viewControllers![0]
self.pageControl.currentPage = orderedViewControllers.index(of: pageContentViewController)!
}
// MARK: Data source functions.
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.index(of: 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
// Uncommment the line below, remove the line above if you don't want the page control to loop.
// return nil
}
guard orderedViewControllers.count > previousIndex else {
return nil
}
return orderedViewControllers[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = orderedViewControllers.index(of: 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
// Uncommment the line below, remove the line above if you don't want the page control to loop.
// return nil
}
guard orderedViewControllersCount > nextIndex else {
return nil
}
return orderedViewControllers[nextIndex]
}
}
import UIKit
class ThirdViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You need to use UiPagerViewDatasource methods :
a) func pageViewController(UIPageViewController, viewControllerBefore: UIViewController)
b) func pageViewController(UIPageViewController, viewControllerAfter: UIViewController)
Example:
func pageViewController(UIPageViewController, viewControllerBefore: UIViewController){
if viewController == controllerA {
return controllerB;
}
else if viewController == controllerB {
return controllerC;
}
else ifviewController == controllerC {
return nil;
}}
and
func pageViewController(UIPageViewController, viewControllerAfter: UIViewController){
if (viewController == controllerC) {
return controllerB;
}
else if(viewController == controllerB) {
return controllerA;
}
else {
return nil;
}}
Sets the view controllers to be displayed you need to call :
pager.setViewControllers([selectingViewController]?, direction: UIPageViewControllerNavigationDirectionForward, animated: false, completion:nil)

Transition between View Controllers with button (UIPageViewController Items)

I have 2 UIViewControllers as items of UIPageViewController. It works well for slide, but i want to move from pageOne to pageTwo with button's action. How i can do that?
Here is my code and storyboard preview:
Contents of Pager.swift :
import UIKit
class Pager: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource, UIScrollViewDelegate
{
var viewsArray: [UIViewController] = []
var pageOne: UIViewController = UIViewController()
var pageTwo: UIViewController = UIViewController()
var currentIndex = 0
var previousIndex = 0
var nextIndex = 0
override func viewDidLoad()
{
super.viewDidLoad()
self.delegate = self
self.dataSource = self
pageOne = (storyboard?.instantiateViewController(withIdentifier: "pageOne"))!
pageTwo = (storyboard?.instantiateViewController(withIdentifier: "pageTwo"))!
viewsArray.append(pageOne)
viewsArray.append(pageTwo)
setViewControllers([pageOne], direction: .forward, animated: true, completion: nil)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
{
currentIndex = viewsArray.index(of: viewController)!
if currentIndex == 1
{
return nil
}
else
{
nextIndex = abs((currentIndex + 1) % viewsArray.count)
return viewsArray[nextIndex]
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?
{
currentIndex = viewsArray.index(of: viewController)!
if currentIndex == 0
{
return nil
}
else
{
previousIndex = abs((currentIndex - 1) % viewsArray.count)
return viewsArray[previousIndex]
}
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int
{
return viewsArray.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int
{
return 0
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
Contents of PageOne.swift :
import UIKit
class PageOne: UIViewController
{
var pager = Pager()
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
#IBAction func forwardButton(_ sender: Any)
{
pager.setViewControllers([pager.pageOne], direction: .forward, animated: true, completion: nil)
}
}
You need to write below line
pageController?.setViewControllers([YOUR_VIEW_CONTROLLER], direction: direction, animated: true, completion: nil)
give proper direction either forward or reverse based on which controller you are at
hope this will help you
You need to pass pager to your both viewcontrollers
pageOne.pager = self
pageTwo.pager = self

Get real index of dynamic pages uiviewcontroller

How can I get the 'real' current index of the active page? I have tried every solution on stack overflow with no luck. So vc.pageIndex gives me the wrong value back. How can I solve this?
My code:
import UIKit
class PageControl: BasePageViewController, UIPageViewControllerDataSource {
var pageViewController: UIPageViewController!
var pageTitles: [[String]]!
var pageImages: NSArray!
var complete : CGFloat = 0.0;
override func viewDidLoad(){
super.viewDidLoad()
HealthKit().recentSteps() { steps, error in
self.pageTitles = steps;
self.pageViewController = self
self.pageViewController.dataSource = self
let startVC = self.viewControllerAtIndex(0) as StepsDetailViewController
let viewControllers = NSArray(object: startVC)
dispatch_async(dispatch_get_main_queue(), {
self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .Forward, animated: true, completion: nil)
})
}
}
override func percentCompleteDidChange() {
if let percentComplete = self.percentComplete {
complete = percentComplete
let vc: StepsDetailViewController = self.storyboard?.instantiateViewControllerWithIdentifier("StepsDetailViewController") as! StepsDetailViewController
vc.updateProgressComplete(percentComplete, index: 0)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func viewControllerAtIndex(index: Int) -> StepsDetailViewController
{
if ((self.pageTitles.count == 0) || (index >= self.pageTitles.count)) {
return StepsDetailViewController()
}
let vc: StepsDetailViewController = self.storyboard?.instantiateViewControllerWithIdentifier("StepsDetailViewController") as! StepsDetailViewController
vc.titleText = self.pageTitles[index][0]
vc.stepData = self.pageTitles[index][1]
vc.pageIndex = index
return vc
}
// MARK: - Page View Controller Data Source
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
{
let vc = viewController as! StepsDetailViewController
var index = vc.pageIndex as Int
if (index == 0 || index == NSNotFound)
{
return nil
}
index -= 1
return self.viewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let vc = viewController as! StepsDetailViewController
var index = vc.pageIndex as Int
if (index == NSNotFound){
return nil
}
index += 1
if (index == self.pageTitles.count)
{
return nil
}
return self.viewControllerAtIndex(index)
}
}

How to retrieve value from extension in view controller swift

I want to retrieve the value from the scrollViewDidScroll function at my view controller. It gives the right value back in the console so that's nice.
My view controller:
import UIKit
extension UIPageViewController: UIScrollViewDelegate {
public override func viewDidLoad() {
super.viewDidLoad()
for subView in view.subviews {
if subView is UIScrollView {
(subView as! UIScrollView).delegate = self
}
}
}
public func scrollViewDidScroll(scrollView: UIScrollView) {
let point = scrollView.contentOffset
var percentComplete: CGFloat
percentComplete = fabs(point.x - view.frame.size.width)/view.frame.size.width
print("percentComplete: ", percentComplete)
}
}
class StepsDetailViewController: UIViewController {
var pageIndex: Int!
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Where the view controller came from:
import UIKit
class PageControl: UIPageViewController, UIPageViewControllerDataSource {
var pageViewController: UIPageViewController!
var pageTitles: [[String]]!
override func viewDidLoad(){
super.viewDidLoad()
testC().getRecent() { result, error in
self.pageTitles = result;
self.pageViewController = self
self.pageViewController.dataSource = self
let startVC = self.viewControllerAtIndex(0) as StepsDetailViewController
dispatch_async(dispatch_get_main_queue(), {
let viewControllers = NSArray(object: startVC)
self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .Forward, animated: true, completion: nil)
})
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func viewControllerAtIndex(index: Int) -> StepsDetailViewController
{
if ((self.pageTitles.count == 0) || (index >= self.pageTitles.count)) {
return StepsDetailViewController()
}
let vc: StepsDetailViewController = self.storyboard?.instantiateViewControllerWithIdentifier("StepsDetailViewController") as! StepsDetailViewController
vc.pageIndex = index
return vc
}
// MARK: - Page View Controller Data Source
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
{
let vc = viewController as! StepsDetailViewController
var index = vc.pageIndex as Int
if (index == 0 || index == NSNotFound)
{
return nil
}
index -= 1
return self.viewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let vc = viewController as! StepsDetailViewController
var index = vc.pageIndex as Int
if (index == NSNotFound)
{
return nil
}
index += 1
if (index == self.pageTitles.count)
{
return nil
}
return self.viewControllerAtIndex(index)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int
{
return self.pageTitles.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int
{
return 0
}
}
Is this possible?
You could do like this:
1. Replace your extension with a custom UIPageViewController
class BasePageViewController: UIPageViewController, UIScrollViewDelegate {
var percentComplete: CGFloat = 0.0 {
didSet { self.percentCompleteDidChange() }
}
func percentCompleteDidChange() {
print("percentCompleteDidChange")
}
public override func viewDidLoad() {
super.viewDidLoad()
for subView in view.subviews {
if subView is UIScrollView {
(subView as! UIScrollView).delegate = self
}
}
}
public func scrollViewDidScroll(scrollView: UIScrollView) {
let point = scrollView.contentOffset
self.percentComplete = fabs(point.x - view.frame.size.width)/view.frame.size.width
print("percentComplete: ", percentComplete)
}
}
2. PageControl is a BasePageViewController subclass
class PageControl: BasePageViewController, UIPageViewControllerDataSource {
// here you have the access to percentComplete of superclass
func printPercentComplete() {
if let percentComplete = self.percentComplete {
print(percentComplete)
}
}
override func percentCompleteDidChange() {
print("percentCompleteDidChange from child")
}
......
}
Define the percentComplete as a property of your custom class that inherits from UIPageViewController.
Then you can access it everywhere.

Delete Image from UIPageViewController

I have a PageViewController set up so that I can add photos from camera or library and the pageviewcontroller resets itself every time the imagepickercontroller is called so the pageviewcontrol updates and shows. It works perfectly (i think). What i know want to do is have the option to delete one of the photos then call the same reset.
The problem is, i can not get an accurate index value of the current image being displayed in the pageviewcontroller. I try to grab the index from the viewControllerBeforeViewController or AfterViewController or the pagecontrolleratindex... but the index does not follow correctly the way the pagecontrol is designed. I read about willtransitiontoviewcontrollers and didfinsihanimating, but those are not being called, i am thinking because i am getting the images from an array and not new view controllers.
My method to delete works, but the index is not accurate so even though the second image is shown the first image could be the one deleted.
Is there a good way to get the current displayed array index so i can delete the image from array? //this array holds images from imagepicker, i call the restartviewcontrollers evertime there is an imagepicked to update the number of pages and this works.
UPDATE
var pageViewController:UIPageViewController!
var pageImages: [UIImage]? = [] //this array holds images from imagepicker, i call the restartviewcontrollers evertime there is an imagepicked to update the number of pages and this works.
var deletePageIndex: Int = 0
func pageViewControllerAtIndex(index: Int) -> PhotoContentPageViewController {
if (self.pageImages!.count == 0 || index >= self.pageImages!.count) {
return PhotoContentPageViewController()
}
var vc = self.storyboard?.instantiateViewControllerWithIdentifier("PhotoPageContentStoryBoard") as! PhotoContentPageViewController
vc.imageFileName = pageImages![index] as! UIImage
vc.pageIndex = index
return vc
}
func restartViewController() {
var startVc = self.pageViewControllerAtIndex(0) as PhotoContentPageViewController
var viewControllers = NSArray(object: startVc)
self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .Forward, animated: true, completion: nil)
}
func startViewControllers() {
self.pageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PhotoPageViewControllerStoryBoard") as! UIPageViewController
self.pageViewController.dataSource = self
pageViewController.delegate = self
var startVc = self.pageViewControllerAtIndex(0) as PhotoContentPageViewController
var viewControllers = NSArray(object: startVc)
self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .Forward, animated: true, completion: nil)
self.pageViewController.view.frame = CGRectMake(0, -10, self.view.frame.size.width, self.view.frame.size.height-30)
self.addChildViewController(self.pageViewController)
self.view.addSubview(self.pageViewController.view)
self.pageViewController.didMoveToParentViewController(self)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
var vc = viewController as! PhotoContentPageViewController
var index = vc.pageIndex as Int
if (index == 0 || index == NSNotFound) {
return nil
}
index--
return self.pageViewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
var vc = viewController as! PhotoContentPageViewController
var index = vc.pageIndex as Int
if (index == NSNotFound) {
return nil
}
index++
if (index == self.pageImages!.count) {
return nil
}
return self.pageViewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
}
func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if (!completed) {
return
}
}
`
If you actually are using a UIPageViewControllerDelegate, you can use willtransitiontoviewcontrollers but that method only works if you set the delegate property of the page view controller to your view controller. That way, you can simply get the index of the current view controller in page view controller and use it for deletion.
myPageViewController.delegate = self
And make sure your view controller implements UIPageViewControllerDelegate
UPDATE
Assuming that you have an array of you view controllers, you could implement your data source like this:
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
if let index = pages.indexOf(viewController)?.advancedBy(1) where index < pages.count {
return pages[index]
}
return nil
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
if let index = pages.indexOf(viewController)?.advancedBy(-1) where index > -1 {
return pages[index]
}
return nil
}