PageViewController showing the index of the page incorrectly? - ios

I have followed this tutorial for creating PageViewController http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/
What the problem is iam getting of the page incorrectly rest of the things all are perfect
I need to do something like if the page index is the last index then i have change the buttons label.
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (([self.pageImages count] == 0) || (index >= [self.pageImages count])) {
return nil;
}
// Create a new view controller and pass suitable data.
PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageContentViewController"];
pageContentViewController.imageFile = self.pageImages[index];
pageContentViewController.titleText = self.pageTitles[index];
pageContentViewController.pageIndex = index;
NSLog(#"INDEX : %lu", (unsigned long)index);
return pageContentViewController;
}
- (void)pageViewController:(UIPageViewController *)pageViewCntr didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
NSInteger currentIndex = ((UIViewController *)self.pageViewController.viewControllers.firstObject).view.tag;
if (completed) pageControl.currentPage = currentIndex;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSInteger index = ((PageContentViewController *)viewController).pageIndex;
if (index == NSNotFound || !index) return nil;
NSLog(#"INDEX : %lu", (unsigned long)index);
return [self viewControllerAtIndex:index-1];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSInteger index = ((PageContentViewController *)viewController).pageIndex;
if (index == NSNotFound || index == pageCount-1) return nil;
NSLog(#"INDEX : %lu", (unsigned long)index);
return [self viewControllerAtIndex:index+1];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{
return [self.pageImages count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{
return 0;
}
I tried many way but couldn't resolve the problem.
Help me in finding the current index of the page.
Index of the page is not showing currently when i swipe one time it returns me 0,1 index at a time and for next swipe it shows me 2 and for next swipe it does not return me any index

I have implemented the same code and after debugging, got to know that the PageViewControllerDataSource methods are getting called twice. So you can use willTransitionToViewControllers method instead of viewControllerBeforeViewController and viewControllerAfterViewController methods to get the proper index.
Please refer following answer,
PageViewController delegate functions called twice

Related

How to manage multiple pageIndicator on run time

How we can show more then 30 pageIndicator in UIPageControl in objective C, its going out from UIPageControl view.
Is there any way to manage that in 10 - 10 blocks/segment at one time.
I am using following code :
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [(DetailOfferViewController *)viewController index];
if (index ==0 ) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [(DetailOfferViewController *)viewController index];
index++;
if (index == [_data count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
return [_data count];
//_data count coming with more then 30 numbers
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
return [_rowNumber intValue];
}
Per Apple's Documentation on UIPageControl:
On iPhone and iPod touch, about 20 page control dots fit on the screen before they are clipped.

UIPageViewControllerDataSource calls viewControllerAfterViewController twice the first time running

I know this might be a duplicate but I tried other solutions found online and none of them seemed to solve my problem.
I have a pageViewController that displays 4 UIViewControllers.
At first scroll the pageController swipes to the third View controller but shows the second ViewController.
Here is my code:
_contentPageRestorationIDs = [[NSArray alloc]initWithObjects:#"PRPeripheralsOriantaionVC",#"PRSessionAnalysisDataVC", #"PRNavigationVC",#"PRVideoVC", nil];
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return self.contentPageRestorationIDs.count;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSString *vcRestorationID = viewController.restorationIdentifier;
NSUInteger index = [self.contentPageRestorationIDs indexOfObject:vcRestorationID];
NSLog(#"viewControllerBeforeViewController %#",vcRestorationID);
if (index == 0)
{
return nil;
}
index--;
return [self viewControllerAtIndex:index ];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSString *vcRestorationID = viewController.restorationIdentifier;
NSLog(#"viewControllerAfterViewController %#",vcRestorationID);
NSUInteger index = [self.contentPageRestorationIDs indexOfObject:vcRestorationID];
index ++;
if (index == self.contentPageRestorationIDs.count )
{
return nil;
}
return [self viewControllerAtIndex:index ];
}
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers
{
NSLog(#"willTransitionToViewControllers %# %lu",pendingViewControllers,(unsigned long)index);
}
-(void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
NSLog(#"didFinishAnimating %#",previousViewControllers);
}
You have a bug, Update your datasource method:
h File
#interface ViewController : UIPageViewController
#end
m File
#import "ViewController.h"
#interface ViewController ()<UIPageViewControllerDataSource>
#property (strong, nonatomic) NSArray *pageColors;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageColors = #[#"green", #"yellow", #"black", #"red"];
self.dataSource = self;
UIViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Private method
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (([self.pageColors count] == 0) || (index >= [self.pageColors count])) {
return nil;
}
NSString* pageColor = self.pageColors[index];
// Create a new view controller and pass suitable data.
UIViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:pageColor];
return pageContentViewController;
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
NSString * identifier = viewController.restorationIdentifier;
NSUInteger index = [self.pageColors indexOfObject:identifier];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
NSString * identifier = viewController.restorationIdentifier;
NSUInteger index = [self.pageColors indexOfObject:identifier];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageColors count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return [self.pageColors count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
#end
Don't forget to change for each view controller the Storyboard ID with his color ([#"green", #"yellow", #"black", #"red"]).
For example, for the read view controller:
You can find here very useful tutorial.
The correct way to do that is to define pageIndex property for each view controller, and then set it in the page view delegate methods, using the view controller at index method, your final wanted code should be the page view delegate methods, passing an index to the view controller at index path and returning there retrieved VC and that's it.

UIPageViewController page indicator out of sync

My UIPageViewController's page indicator goes out of sync when swiping back and forth really fast using this UIAutomation script:
target.dragFromToForDuration({x:10, y:100}, {x:300, y:114}, 0.5);
target.dragFromToForDuration({x:300, y:100}, {x:10, y:114}, 0.5);
repeated over and over.
Or when tapping one direction on the page controller and swiping the other direction as in this question:
UIPageControl and UIPageviewController are out of sync
The solution there was to replace the page indicator with a UIPageControl. This solution was also accepted here:
Page Indicator UIPageViewController
My code for returning the UIViewControllers (the UIViewControllers contain tables with different data sources):
- (MyViewController*) viewControllerAtIndex:(NSUInteger)index
{
MyViewController *pageContentViewController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
id myDataSource = [self.myDataSources objectAtIndex:index];
[pageContentViewController setMyDataSource:myDataSource];
return pageContentViewController;
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
id myDataSource = [((MyViewController*) viewController) myDataSource];
NSInteger index = [self.myDataSources indexOfObject:myDataSource];
if (index == NSNotFound || index - 1 < 0) {
return nil;
} else {
MyViewController *pageContentViewController = [self viewControllerAtIndex:index - 1];
return pageContentViewController;
}
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
MyDataSource *myDataSource = [((MyViewController*) viewController) myDataSource];
NSInteger index = [self.myDataSources indexOfObject:myDataSource];
if (index == NSNotFound || index + 1 >= [self.myDataSources count]) {
return nil;
} else {
MyViewController *pageContentViewController = [self viewControllerAtIndex:index + 1];
return pageContentViewController;
}
return nil;
}
What is causing the UIPageViewController and page indicator to become out of sync?

How can I program the UIPageViewController to navigate through two separate views?

I've asked this question before, and I haven't got any solid answers, I am determined to find the solution not take up too much time, so I added images through Google sites.
I'd like to navigate with Page Control from View 1 to view 2 which are 2 separate view controllers.
pic one xcode
Pic 2 story board
Additional code that needs fixing:
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageTitles count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return [self.pageTitles count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
I just need the UIPageViewController to navigate from view 1 to view 2 and back to view 1 from view 2.
Hi you have to use this method also
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
return nil;
}
// Create a new view controller and pass suitable data.
PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageContentViewController"];
//pageContentViewController.imageFile = self.pageImages[index];
pageContentViewController.titleText = self.pageTitles[index];
pageContentViewController.pageIndex = index;
return pageContentViewController;
}
or refer this links hope it will work for you.
http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/
Thanks

syncing UIPageViewController with UISegmentedControl logic issue

I want a segmented control to act like the gray dots at the bottom of the page of a pageview controller. So, when I swipe to the right, it moves to the segment on the right, and when I swipe to the left, it moves to the segment on the left. I've already got it to change the page when I click on a specific segment correctly (so if I click the first segment, it moves to the first page). However, I can't seem to make the code do exactly what I want it to do. Right now I have the following code:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers
{
if([pendingViewControllers count]>0)
{
NSUInteger index =[(MasterTableViewController*)[pendingViewControllers objectAtIndex:0] pageIndex];
segmentedControl.selectedSegmentIndex = index;
}
}
This works fine, but the problem is that this is called when the transition is happening, not when it is finished. Therefore, when I start changing the page, but then stop, it moves the segment over. So, I tried some other code:
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
if(finished && completed && [previousViewControllers count]>0)
{
NSUInteger index =[(MasterTableViewController*)[previousViewControllers objectAtIndex:0] pageIndex];
segmentedControl.selectedSegmentIndex = index;
self.lastSelected = index;
}
}
This is called at the right time. If I put an NSLOG, it shows up ever time I finish a transition, which is exactly what I want, but for some reason, the segmentcontrol is lagged behind by 1 move. So, if I go from page 1 to page 2, segment stays at 1, and then if i go from page 2 to page 3, segment moves to 2, and then from then on it continues to lag behind by one move no matter which direction I go. I've played around with it and I can't seem to get the logic straight. Help would be greatly appreciated!!
Here are the helper functions:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = ((MasterTableViewController*) viewController).pageIndex;
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((MasterTableViewController*) viewController).pageIndex;
if (index == NSNotFound) {
return nil;
}
index++;
// startingViewController.pageIndex = index;
if (index == [self.pageTitles count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (MasterTableViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
return nil;
}
MasterTableViewController *pageContentViewController;
if (index == 0)
{
pageContentViewController = [storyboard instantiateViewControllerWithIdentifier:#"OnCampusTable"];
}
else if (index == 1)
{
pageContentViewController = [storyboard instantiateViewControllerWithIdentifier:#"OffCampusTable"];
}
else if (index == 2)
{
pageContentViewController = [storyboard instantiateViewControllerWithIdentifier:#"MyEventsTable"];
}
// pageContentViewController.titleText = self.pageTitles[index];
pageContentViewController.pageIndex = index;
return pageContentViewController;
}
Any of the commented stuff was stuff I was playing with to try to get the logic straight. I just ran the program with didFinishAnimating running and willTransitionToViewControllers commented out. This gave the lagged effect where the segmented control is one behind the cells. Any help is very appreciated
this is how i solved it:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers
{
if([pendingViewControllers count]>0)
{
NSUInteger index =[(MasterTableViewController*)[pendingViewControllers objectAtIndex:0] pageIndex];
startingViewController.pageIndex = index;
}
}
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
if(finished && completed && [previousViewControllers count]>0)
{
NSUInteger index =[(MasterTableViewController*)[previousViewControllers objectAtIndex:0] pageIndex];
segmentedControl.selectedSegmentIndex = startingViewController.pageIndex;
self.lastSelected = index;
}
}
Essentially, I used both the willTransition and the didFinishAnimation. When you call a transition, the method changes a global variable, pageIndex, to get the page index, but doesn't change the segment. When you finish the animation, the didFinish method pulls the global pageIndex, and sets the segment to be that page.
You could just use didset method:
var pageIndex:Int!{
didSet{
segmentControl.selectedSegmentIndex = pageIndex
}
}

Resources