How to jump between two UIViewcontrollers - ios

I want to jump between two UIViewcontrollers
through swipe action.
Currently, I implemented a UIScrollView, and added UIViewcontrollers(vc1 and vc2) on it, so
On vc1
swipe left : jump to vc2
swipe right : do nothing
On vc2
swipe left : do nothing
swipe right : jump to vc1
But what I want is:
On vc1
swipe left : jump to vc2
swipe right : jump to vc2
On vc2
swipe left : jump to vc1
swipe right : jump to vc1
So, how to achieve?

Try this
Steps:
In your view controller Create a UIPageViewController
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
Add your both view controller on UIPageViewController
NSArray *viewControllers = //add your two view controllers in array;
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
Set data source and Add UIPageViewController as child view controller
self.pageController.dataSource = self;
[self addChildViewController:self.pageController];
Now, You need to implement two methods
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(ViewController *)viewController index];
if (index == 0) {
return nil;
}
// Decrease the index by 1 to return
index--;
return viewControllers[index];//[self viewControllerAtIndex:index];//viewControllerAtIndex
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(ViewController *)viewController index];
if (index == 1) {
return nil;
}
index++;
return viewControllers[index];
}

Related

How to go next page ++ in UIPageviewController when i click UIButton in iOS

Now I am creating app tour for my app by using uipageviewcontroller, its working fine when I am swipe the pages in view controller but what I need was the page will move when I click the button
below is my button click action here i can able to put only custom page index but I need to give the current page of the index
- (IBAction)donebtnaction:(id)sender {
NSLog(#"current page: %#",indexpathpage);
PageContent *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.PageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
}
and i am also tried to save the index when swipe after and swipe before,
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController{
NSUInteger index = ((PageContent*) viewController).pageIndex;
if (index == NSNotFound){
return nil;
}
index++;
[self.pagecontrol setCurrentPage:index];
if (index == [self.arrPageTitles count])
{
return nil;
}
return [self viewControllerAtIndex:index];
}
Please give me solution for this .
Try navigating the page by pop and push actions . That will help to which action u are performing and which indexPath its heading .
For example for push which is inserting from stack
xController *xVC = [[xController alloc]init];
xVC.view.backgroundColor = [UIColor whiteColor];
[self.navigationController pushViewController:xVC animated:YES];}
for example to pop which means taking it out from the stack
[self.navigationController popViewControllerAnimated:YES];

Is there way to get all the pre-loaded view controllers in UIPageViewController

I have an UIPageViewController. I can flip the pages and everything works fine. The UIPageViewController pre-loads one ViewController. At this point, there are two view controllers in memory (one is the visible controller while another is the pre-loaded controller). I want to get the two ViewControllers so that I could change some settings on the fly.
The question is how could I get the pre-loaded child view controllers? If I cannot get those controllers, what is the best way to reset some properties on all the preloaded view controllers?
You can modify your custom object which can be used to build your view controller:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(PageChildViewController *) viewController index];
if (index == 0) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index {
CustomObject *customObject = self.customObjects[index];
PageChildViewController *childViewController = [PageChildViewController controllerWithIndex:index andCustomObject:customObject];
return childViewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(PageChildViewController *) viewController index];
index++;
if (index == self.pages.count) {
return nil;
}
return [self viewControllerAtIndex:index];
}
If you need to update currently visible page view controller you can use this:
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
If you need to reset you page view controller cache you can use this:
self.pageController.dataSource = nil;
self.pageController.dataSource = self;

UI Page View Controller Scroll Won't Scroll Backwards

I have implemented a UIPageViewController that I want to be able to scroll infinitely to the right (as in the user swipes to the left) and be able to scroll backwards in the other direction all the way to the start. However I don''t want the user to be able to scroll left (as in the user swipe to the right) on the very first page, even though I only have three pages that loop, how can I do this?
I have already figured out how to make an infinite scroll with three view controllers to the right ( as in user scrolls to the left) but when the user tries to scroll to the left (as in user swipes to the right) it bugs out and the screen goes white?
Can anyone improve on this code so the user can infinitely scroll both ways, not just one? and if possible prevent the user from scrolling backwards on the very first panel? thanks.
PageViewController.h
#import <UIKit/UIKit.h>
#interface PageViewController : UIPageViewController
<UIPageViewControllerDelegate, UIPageViewControllerDataSource>
#end
PageViewController.m
#import "PageViewController.h"
#interface PageViewController ()
#end
#implementation PageViewController
{
NSArray *myViewControllers;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = self;
self.dataSource = self;
UIViewController *p1 = [self.storyboard
instantiateViewControllerWithIdentifier:#"ContentViewController1"];
UIViewController *p2 = [self.storyboard
instantiateViewControllerWithIdentifier:#"ContentViewController2"];
UIViewController *p3 = [self.storyboard
instantiateViewControllerWithIdentifier:#"ContentViewController3"];
myViewControllers = #[p1,p2,p3];
[self setViewControllers:#[p1]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO completion:nil];
NSLog(#"loaded!");
}
-(UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
return myViewControllers[index];
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [myViewControllers indexOfObject:viewController];
--currentIndex;
currentIndex = currentIndex % (myViewControllers.count);
return [myViewControllers objectAtIndex:currentIndex];
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [myViewControllers indexOfObject:viewController];
++currentIndex;
currentIndex = currentIndex % (myViewControllers.count);
return [myViewControllers objectAtIndex:currentIndex];
}
-(NSInteger)presentationCountForPageViewController:
(UIPageViewController *)pageViewController
{
return myViewControllers.count;
}
-(NSInteger)presentationIndexForPageViewController:
(UIPageViewController *)pageViewController
{
return 0;
}
#end
You can use Flag to know the initial View (first view).then use this scroll enable and disable method to prevent the swipe.
-(void)setScrollEnabled:(BOOL)enabled forPageViewController:(UIPageViewController*)pageViewController{
for(UIView* view in pageViewController.view.subviews){
if([view isKindOfClass:[UIScrollView class]]){
UIScrollView* scrollView=(UIScrollView*)view;
[scrollView setScrollEnabled:enabled];
return;
}
}
Hope this Will Work.

UIPageViewController with different ViewControllers, right way?

Basically, I have a Table View Controller and a normal View Controller, I want to make it so that I can swipe between the view controllers like on the home screen of app (obvious same type of view controller).
But the thing I am finding is that the UIpageviewcontroller is usaully used when you have multiple views of the same type of viewcontroller for example swiping between pictures, you could just set an index in the class and an array of images relating to the index and set it up that way.
But I'm trying to get different view controllers in this set up. Right now it's two but will definitely go up to about 4.
Is UIPageViewController the right way to set it up or something else.
EDIT: Code added below
//
// ViewController.m
// testb
//
#import "MainPostController.h"
#import "MainTableViewController.h"
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize pageViewController;
#synthesize indexValue = _indexValue;
- (void)viewDidLoad
{
[super viewDidLoad];
self.indexValue= 1;
NSLog(#"main intitated");
// Do any additional setup after loading the view, typically from a nib.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
MainTableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainTableViewController"];
MainPostController *pvc;
NSArray *viewcontrollers =[NSArray arrayWithObjects:tvc, pvc, nil];
[self.pageViewController setViewControllers:viewcontrollers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:pageViewController];
[self.view addSubview:pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if (self.indexValue == 1) {
MainPostController *pvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainPostController"];
self.indexValue = 0 ;
return pvc;
}
else return nil;
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if (self.indexValue == 0) {
MainTableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainTableViewController"];
self.indexValue = 1;
return tvc;
}
else return nil;
}
#end
I want the intial view to be the table view controller(tvc) and i want the Post view controller(pvc) to be to its left. I can load it up and swipe between the two easily but sometime i can swipe further than the boundaries so basically if i start on the tvc-->pvc-->tvc then i can go further by swiping right to the same tvc then the boundary is reached or go the other way tvc-->pvc-->tvc-->pvc-->pvc by swiping left for the last transition. The boundaries are reached in the end. Once the app intially launches at tvc i cannot go forward a page, (which is what should happen) and if i go tvc-->pvc and try to go to a page to the left it wont let me (which is what should happen)
Thanks
Finally done it, didn't have to add any properties to the different classes. Just tested the class. Heres the code:
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[MainTableViewController class]]) {
MainPostController *pvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainPostController"];
return pvc;
}
else return nil;
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[MainPostController class]]) {
MainTableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainTableViewController"];
return tvc;
}
else return nil;
}
Should be easy to add more view controllers as i just need to add else if statements to test them. The main problem solver was the method isKindOfClass:
Thanks for your reply guys!
I had the same issue, here's what i did and working perfectly.
.h
#interface ViewController : UIViewController <UIPageViewControllerDataSource>
#property (strong, nonatomic) UIPageViewController *pageViewController;
#property (nonatomic) NSArray *viewControllerIDArr;
#end
.m
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupDefaults];
}
- (void)setupDefaults
{
self.viewControllerIDArr = #[#"FirstViewController", #"SecondViewController"];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
UIViewController *startingViewController = [self.storyboard instantiateViewControllerWithIdentifier:self.viewControllerIDArr[0]];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 45);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
- (UIViewController *)getViewControllerFromClass:(Class)class isNext:(BOOL)next
{
NSInteger index = [self.viewControllerIDArr indexOfObject:[NSString stringWithFormat:#"%#", class]];
if (next)
index+=1;
else
index-=1;
if (index < 0 || index >= self.viewControllerIDArr.count)
return nil;
else
return [self.storyboard instantiateViewControllerWithIdentifier:self.viewControllerIDArr[index]];
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
return [self getViewControllerFromClass:viewController.class isNext:NO];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
return [self getViewControllerFromClass:viewController.class isNext:YES];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
Note:
self.viewControllerIDArr containers Storyboard ID's of the viewControllers.
It looks like this in storyboard:
This is an old question but since I bumped into this problem I'll post my solution.
The first time I did this I added my code
func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { }
Which received problems when you continuously scroll the views using two fingers and didFinishAnimating is not called unless scrolling stops.
So I just used this delegate method instead.
func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
let currentView = pendingViewControllers[0]
if currentView is UINavigationController && currentView.restorationIdentifier == "Settings" {
index = 0
} else if currentView is UINavigationController && currentView.restorationIdentifier == "Main" {
index = 1
} else if currentView is UINavigationController && currentView.restorationIdentifier == "Message" {
index = 2
}
}
Where currentView is the currentUIViewController (or UINavigationController like what I am using, using a restorationIdentifier to identify my navigation controller as well), and index is a global value to know which UIViewController in the array to instantiate.
You could use a UIViewPageViewController, with some custom logic.
As you say, the normal way to handle this is to have the page view controller's data source simply create the same type of view controller for each page and fill it with data from your model.
In your case, you could add a pageNumber property to all the view controllers that you're going to host in your page view controller. Then, in the data source methods, use the page number of the old view controller to figure out the new page number. Then have a switch statement based on page number. Each case in the switch statement would create a different type of view controller.

Using View Controller from storyboard programmatically in a Page View Controller

I have an app with a storyboard. I am using several View Controller with segues to choose from a table view depending on the item selected. I want to have a page view controller in which the pages will be one or more view controller from the storyboard, even repeating them. I am trying to init the Page View Controller like this:
....
self.dataSource=self;
UIViewController *initialViewController =[self viewControllerAtIndex:current];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self setViewControllers:viewControllers direction:UIPageViewControllerNavigationOrientationHorizontal animated:NO completion:nil];
....
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
if ((descriptions.count == 0) ||
(index >= descriptions.count)) {
return nil;
}
current=index;
// Create a new view controller and pass suitable data.
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
Description *description=[DBCompany getDescriptionById:language descriptionId:[[descriptions objectAtIndex:index] integerValue]];
UIViewController *viewController=nil;
if(description.frame==100){
viewController=[[Company100ViewController alloc] init];
((Company100ViewController*)viewController).companyId = companyId;
}
return viewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if ((descriptions.count == 0) ||
(current-1 < 0)) {
return nil;
}
return [self viewControllerAtIndex:current-1];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if ((descriptions.count == 0) ||
(current >= descriptions.count)) {
return nil;
}
return [self viewControllerAtIndex:current+1];
}
However the viewcontroller appears in black. I think is because I am adding the UIviewcontroller class but not connecting it to any view, XIB, in my case with the storyboard.
How can I use the different view controller from the storyboard programmatically to use in a page view controller?
If you do viewController=[[Company100ViewController alloc] init] then yes this not a controller that is associated to a storyboard or an XIB. To load the controller with an XIB you have to do the following:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
Company100ViewController * vc = (Company100ViewController *)[sb instantiateViewControllerWithIdentifier:#"vc-identifier"];
In the storyboard make sure you set the view controller's id to vc-identifier; whatever identifier you choose.
Swift 3
let sb = UIStoryboard(name: "MainStoryboard", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "vc-identifier")
Swift
In case you want to init from a UIViewController object.
guard let vc = storyboard?.instantiateViewController(withIdentifier: "nameVC") else {
return
}
// add to current view
view.addSubview(vc.view)

Resources