I have two storyboards with identifiers "one" and "two", I have a UIPageViewController and a subclass of it. In the subclass I have this code below:
- (void)viewDidLoad
{
[super viewDidLoad];
self.dataSource = self;
self.delegate = self;
counter = 0;
[self setViewControllers:#[[self.storyboard instantiateViewControllerWithIdentifier:#"one"]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[ViewController class]]){
return [self.storyboard instantiateViewControllerWithIdentifier:#"one"];
}
return nil;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[secondViewController class]]){
return [self.storyboard instantiateViewControllerWithIdentifier:#"two"];
}
return nil;
}
This code works very well, but has a problem! The scroll is infinite; in my case I need to take off the infinite scroll. How I can do this?
First thing is create a counter and do checks inside my methods:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if (counter < 1) {
NSLog(#"Don't get back");
return nil;
}
......
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if (counter >= 1) {
NSLog(#"Don't go anymore");
return nil;
}
....
}
The second thing is try to use counter++ and counter--. This is being a big puzzle to me, anyone have any better ideas?
If you only have two pages, then simply check when you get a request for a page, if the current page is not already the one you would serve. For this, you need a way to identify it.
If each of the pages has a different class, you can simply check for the class. Otherwise you'll need some other criterion.
If using custom classes:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[ClassOfSecondViewController class]])
{
return [self.storyboard instantiateViewControllerWithIdentifier:#"one"];
}
return nil;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[ClassOfFirstViewController class]])
{
return [self.storyboard instantiateViewControllerWithIdentifier:#"two"];
}
return nil;
}
Just a little change in the condition.
- (nullable UIViewController *)pageViewController:(nonnull UIPageViewController *)pageViewController viewControllerBeforeViewController:(nonnull UIViewController *)viewController {
NSUInteger currentIndex = [pages indexOfObject:viewController];
NSUInteger previousIndex = ((currentIndex - 1) % pages.count);
if (viewController == yourFirstViewController)
return nil;
return pages[previousIndex];
}
- (nullable UIViewController *)pageViewController:(nonnull UIPageViewController *)pageViewController viewControllerAfterViewController:(nonnull UIViewController *)viewController {
NSUInteger currentIndex = [pages indexOfObject:viewController];
NSUInteger nextIndex = ((currentIndex + 1) % pages.count);
if (viewController == yourLastViewController)
return nil;
return pages[nextIndex];
}
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
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.
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 to perform the transitions of the uipageviewcontroller from right to left. So I look at this and this examples. But difference is I have one viewcontroller to show at a time and pageViewController:spineLocationForInterfaceOrientation: can only return UIPageViewControllerSpineLocationMin not UIPageViewControllerSpineLocationMax. This is what I have done so far.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(APPChildViewController *)viewController index];
if (index == 0) {
return nil;
}
// Decrease the index by 1 to return
index--;
return [self viewControllerAtIndex:index];}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(APPChildViewController *)viewController index];
index++;
if (index == 15) {
return nil;
}
return [self viewControllerAtIndex:index];}
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation {
UIViewController *currentViewController = [self.pageController.viewControllers objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
self.pageController.doubleSided = NO;
//Return the spine location
return UIPageViewControllerSpineLocationMin;
}
How can I get the curl working properly with the UIPageViewControllerSpineLocationMin?. Also I cannot use Page-Based Application template.
Based on this I found the solution. This is the code.
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation {
UIViewController *currentViewController = [self.pageController.viewControllers objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
self.pageController.doubleSided = NO;
return UIPageViewControllerSpineLocationMax;
}
I have added a UIPageViewController to my project for creating a walkthrough screen, but I can seem to understand how to make this to work using storyboards.
First I have defined the two data source methods: viewControllerBeforeViewController and viewControllerAfterViewController.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(WalktroughScreenPageViewController *)viewController index];
if (index == 0) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(WalktroughScreenPageViewController *)viewController index];
index++;
if (index == 3) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (WalktroughScreenPageViewController *)viewControllerAtIndex:(NSUInteger)index {
WalktroughScreenPageViewController *childViewController = [[WalktroughScreenPageViewController alloc] init];
childViewController.index = index;
return childViewController;
}
Also for showing the dots at the bottom I added this two methods:
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return 3;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
What I can understand it's how to do the setup in ViewDidLoad. I tried something like this which gives me a EXC_BAD_ACCESS error:
- (void)viewDidLoad
{
[super viewDidLoad];
self.dataSource = self;
WalktroughScreenPageViewController *ic = [self viewControllerAtIndex:0];
[self setViewControllers:#[ic] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
}
Can someone point me to the right direction ?