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?
Related
I've UIPageViewController and I can go next and previous page using below delegate methods.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[PageController class]])
return nil;
if(_counter < 1) {
return nil;
}
self.view.backgroundColor = [UIColor lightGrayColor];
return [self.storyboard instantiateViewControllerWithIdentifier:#"memoTable"];
}
Edit:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
//NSLog(#"Child controller count = %lu",(unsigned long)pageViewController.childViewControllers.count);
if ([viewController isKindOfClass:[PageController class]])
return nil;
if([viewController isKindOfClass:[TableViewController class]])
{
TableViewController *viewController1 = (TableViewController*) viewController;
if (viewController1.dataArr.count < 5) {
return nil;
}
}
return [self.storyboard instantiateViewControllerWithIdentifier:#"pageView"];
}
Now I want to go next page if some condition satisfied. Like last page viewController.isCheck == true.
How can I achieve this?
You can just add that condition to one of the existing ifs and return nil if the condition isn't verified. Something like:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[PageController class]] || ((YourViewControllerClass *)viewController).isCheck == false)
return nil;
return [self.storyboard instantiateViewControllerWithIdentifier:#"pageView"];
}
Simply check the view controller you instantiated before returning it in pageViewController:viewControllerAfterViewController method.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[PageController class]])
return nil;
let pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"pageView"];
if (pageViewController.isCheck)
return pageViewController;
else return nil;
}
My second guess is that you should try to instantiate all the view controllers that you will need in the UIPageViewController before you navigate.
UIViewController* memoViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"memoTable"];
UIViewController* pageViewContentController = [self.storyboard instantiateViewControllerWithIdentifier:#"pageView"];
assign all the view controllers you will need in an array
NSArray* reservedViewControllers = #[memoViewController, pageViewController];
use index to track where you current page is
int currentIndex = 0;
Then you can easily iterate between your view controllers in the UIPageViewControllerDataSource functions.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if(currentIndex == 0) return nil;
currentIndex = currentIndex - 1;
return reservedViewControllers[currentIndex];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if(currentIndex == reservedViewControllers.count) return nil;
currentIndex = currentIndex + 1;
//check for last page
if(currentIndex == reservedViewControllers.count){
UIViewController* lastViewController = reservedViewControllers[currentIndex];
if(lastViewController.isCheck == false) return nil;
}
return reservedViewControllers[currentIndex];
}
According to your question you should use the scroll view for this purpose.. set the content size of the scroll view and give the content offset to the content on your table...
for your reference:
see the link:
https://github.com/cwRichardKim/RKSwipeBetweenViewControllers
https://github.com/nicklockwood/SwipeView
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.
I need a dynamic UIPageViewController, the number of pages depends on the quantity of items of my array.
I have two views for this. One for the first page and another one for the other pages. It will be always more than 2 pages (two items on my array).
I'm trying to test with fixed values. But the paging it's not right. The index is not correct.
1st problem, the presentationCountForPageViewController [_vc count] returns nil;
2nd problem, the pagination it's not right. I get to the last page, and the first view it's gone, so if I go back, goes to second view, always...
Please, help!
- (void)viewDidLoad {
[super viewDidLoad];
FirstViewController *agenda = (FirstViewController*)[self viewControllerAtIndex:0];
[_vc addObject:#"FirstViewController"];
[_vc addObject:#"SecondViewController"];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
NSArray *viewControllers = [NSArray arrayWithObject:agenda];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
UIPageControl *pageControlAppearance = [UIPageControl appearanceWhenContainedIn:[UIPageViewController class], nil];
pageControlAppearance.pageIndicatorTintColor = [UIColor lightGrayColor];
pageControlAppearance.currentPageIndicatorTintColor = [UIColor darkGrayColor];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [_vc indexOfObject:viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
//notice here I call my instantiation method again essentially duplicating work I have already done!
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [_vc indexOfObject:viewController];
if (index == NSNotFound) {
return nil;
}
index++;
return [self viewControllerAtIndex:index];
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (index == 0){
FirstViewController *firstController = [self.storyboard instantiateViewControllerWithIdentifier:#"FirstViewController"];
return firstController;
}
else{
SecondViewController *secondController = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
return secondController;
}
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return [_vc count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
As per comments/chat, a few things needed resolving:
You need to instantiate the _vc array
You need to add UIViewControllerobjects to this array, not the strings you currently use
You need to amend the viewControllerBeforeViewController and viewControllerAfterViewController methods to return the relevant element from the _vc array, remembering to test that the index remains within the array's bounds, to prevent swiping beyond the final page, or before the first (agenda) page.
I have searched a lot before posting without success:
I have UIPageViewController with array of UIViewController and PageCurl as transition.
Every UIViewController consists of UIScrollView and UIWebView.
the scroll height calculated based on webview height after loading the content.
now when I load UIPageViewController and start navigation between UIViewController without scrolling the content every thing works fine. But if I scrolled any page and then navigate to the next page or previous one. it will redisplay the same page and then works again normally.
I have tested it on IOS7 and IOS8:
UIPageViewController viewDidLoad method:
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageController.doubleSided = NO;
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
View Controller webViewDidFinishLoad:
CGSize contentSize = aWebView.scrollView.contentSize;
webView.frame = CGRectMake(0, 312, contentSize.width, contentSize.height);
scrollView.contentSize = CGSizeMake(320.f, contentSize.height+60);
Edit
Here is the complete code for viewControllerBeforeViewController and viewControllerAfterViewController of UIPageViewController
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(NewsDetailVC *)viewController index];
self.index = index;
NSLog(#"view before %i", index);
if (index <= 0) {
return nil;
}
index--;
currentViewController = [self viewControllerAtIndex:index];
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(NewsDetailVC *)viewController index];
NSLog(#"view after %i", index);
if (index >= self.newsList.count -1) {
return nil;
}
index++;
currentViewController =[self viewControllerAtIndex:index];
return [self viewControllerAtIndex:index];
}
Edit2
The previous page is an UIViewController contains UITableView when click on a cell will pass the array of Items to UIPageViewController and the selected index.
The purpose of currentViewController because I have controls for font size, and current view background.
The UIPageViewController parent is UIViewController
Here is the code of viewControllerAtIndex:
- (NewsDetailVC *)viewControllerAtIndex:(NSUInteger)index {
NewsDetailVC *childViewController = [[UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"NewsDetailVC"];
childViewController.index = index;
childViewController.selectedNews = [self.newsList objectAtIndex:index ];
childViewController.selectedCategory = self.selectedCategory;
return childViewController;
}
I had the same problem with an UIPageViewController.
It seems like the index shown in viewControllerAtIndex is not quite an accurate one.
As somebody else mentioned in the comment above, in these situations you should implement the delegate method pageViewController:willTransitionToViewControllers.
In this method you should do your work:
- (void)pageViewController:(UIPageViewController *)pageViewController
willTransitionToViewControllers:(NSArray *)pendingViewControllers {
if ([pendingViewControllers count] > 0) {
NSUInteger index = [(PageContentViewController *)
[pendingViewControllers objectAtIndex:0] pageIndex];
if (index == [yourArray count] - 1 || index == 0) {
[self loadContent];
} else {
[self doOtherStuff];
}
}
}
Somehow, the * viewControllerAtIndex* is called several times, giving you troubles finding the index, but in this method the index should be accurate.
Hope it helps!
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