Auto scrolling UIPageViewController in iOS

I am making one application in which a PageViewController element needs to be viewed for some time interval. I am currently doing this prior to manual scrolling. User can scroll any images and it will work. But stuck with auto scrolling with custom touches. Below is my code. Please help me with this.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    _pageTitles = @[@"", @"", @"", @""];
    _pageImages = @[@"page1.png", @"page2.png", @"page3.png", @"page4.png"];

    // Create page view controller
    self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageViewController"];
    self.pageViewController.dataSource = self;

    PageContentViewController *startingViewController = [self viewControllerAtIndex:0];
    NSArray *viewControllers = @[startingViewController];
    [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];

    // Change the size of page view controller
    self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 50);

    [self addChildViewController:_pageViewController];
    [self.view addSubview:_pageViewController.view];
    [self.pageViewController didMoveToParentViewController:self];
}

- (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;
}

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:YES];

    self.navigationController.navigationBar.hidden = YES;
}

#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;
}

      

+1


source to share


3 answers


@Daniel, your link is broken and your "answer" has little to explain your solution to the question. For those interested in reading the documentation for the UIPageViewController class .

Here you should pay attention to the following:

- (void)setViewControllers:(NSArray *)viewControllers
                 direction:(UIPageViewControllerNavigationDirection)direction
                  animated:(BOOL)animated
                completion:(void (^)(BOOL finished))completion

      

The UIPageViewController expects you to tell which data to deliver and which controller to use based on the value. Here I say that my subclass UIPageController is a delegate and dataSouce. After setting up the delegate methods and the dataSource viewControllerAtIndex method, I added a custom interval that calls my loadNextController method. In this method, I check if the "next" controller is null. If it's not nil, I pass the "next" controller as @ [start controller] back to the second call to setViewControllers. If it's nil, I just reset the index value for ZERO and call setViewControllers with my "next" controller as @ [firing controller]. This custom subclass is used to navigate to the next or first controller automatically. The bonus isthat the user experience is still handled by the UIPageViewController class.



Note. The initial call to setViewControllers is required because your UIPageViewContrller will not know what if any viewController can be loaded first. My second call to setViewControllers does nothing more than navigate to the next or first viewController.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.index = 0;
    self.delegate = self;
    self.dataSource = self;

    /*! setup an interval */
    [NSTimer scheduledTimerWithTimeInterval:10.0
                                     target:self
                                   selector:@selector(loadNextController)
                                   userInfo:nil
                                    repeats:YES];

    /*! set starting controller */
    NSArray *startingViewControllers = @[[self  viewControllerAtIndex:self.index]];

    [self setViewControllers: startingViewControllers
                   direction: UIPageViewControllerNavigationDirectionForward
                    animated: YES
                  completion: nil];
}

- (UIViewController*)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    NSUInteger index = ((YSPageContentViewController*) viewController).pageIndex;
    if (index > 0 ) {
        return [self viewControllerAtIndex:index-1];
    }
    return nil;
}

- (UIViewController*)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
    NSUInteger index = ((YSPageContentViewController*) viewController).pageIndex;
    if (index+1 < [self.items count] ) {
        return [self viewControllerAtIndex:index+1];
    }
    return nil;
}

- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index{
    if (index < [self.items count]) {
        PageContentViewController *pageContentViewController =   [[PageContentViewController alloc]init];
        pageContentViewController.pageIndex = index;
        pageContentViewController.image = (UIImage*)self.items[index];
        return pageContentViewController;
    }
    return nil;
}

/*! set next controller */
- (void)loadNextController {
    PageContentViewController *nextViewController = [self viewControllerAtIndex:self.index++];
    if (nextViewController == nil) {
        self.index = 0;
        nextViewController = [self viewControllerAtIndex:self.index];
    }
    [self setViewControllers:@[nextViewController]
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:YES
                  completion:nil];
} 

      

Note. It works; however, I don't always return the correct controller when the internal gesture recognizer changes the controller. Somewhere along the way, I lose track of the index. I'll update this with my finished implementation.

+3


source


Perhaps the method you are looking for is setViewControllers:direction:animated:completion:

Naturally, you will need to supply the view controllers that you want to see at the end of the animation.



You can call this with an animated set to YES and the controller will automatically do the following settings :)

Read more on the documentation for more

0


source


Worked on @ Ryan's answer. Fixed @ Ryan issue "However, I don't always return the correct controller when the internal gesture recognizer changes controller. Somewhere along the way, I lose track of the index."

Just edited a few lines and it worked for me. Thought to share in case someone needs the same.

- (void)viewDidLoad
{
[super viewDidLoad];
_pageTitles = @[@"Tips n Tricks", @"Join to learn", @"Share to get points"];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageViewController"];
self.pageViewController.dataSource = self;
self.pageViewController.delegate = self;

[NSTimer scheduledTimerWithTimeInterval:10.0
                                 target:self
                               selector:@selector(loadNextController)
                               userInfo:nil
                                repeats:YES];
PageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = @[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];

// Change the size of page view controller

self.pageViewController.view.frame = _containerView.frame;
self.pageControl.numberOfPages = _pageTitles.count;
self.pageControl.currentPage = 0;
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
[self.view bringSubviewToFront:self.pageControl];

}

      

Implemented methods of the PageViewController data source

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
    if ((index == 0) || (index == NSNotFound)) {
        index = _pageTitles.count;
    }
    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]) {
        index = 0;
    }
    return [self viewControllerAtIndex:index];
}
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
    if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
        return nil;
    }
    PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageContentViewController"];
    pageContentViewController.titleText = self.pageTitles[index];
    pageContentViewController.pageIndex = index;
    return pageContentViewController;
}

      

Implemented the didFinishAnimating method of the PageController delegate to get the current index of the PageViewController and update the PageControl accordingly

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
    PageContentViewController *currentViewController = pageViewController.viewControllers[0];
    currentIndex = (int)currentViewController.pageIndex;
    [self.pageControl setCurrentPage:currentIndex];
}

      

and in the last implemented method to update the PageViewController on animation

- (void)loadNextController {
    currentIndex++;
    PageContentViewController *nextViewController = [self viewControllerAtIndex:currentIndex];
    if (nextViewController == nil) {
        currentIndex = 0;
        nextViewController = [self viewControllerAtIndex:currentIndex];
    }
    [self.pageViewController setViewControllers:@[nextViewController] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
    [self.pageControl setCurrentPage:currentIndex];
}

      

The current index is declared globally to keep track of the current PageViewController index and update the PageController accordingly.

Hope this helps .. Happy Coding .. :)

0


source







All Articles