本文介绍了无限滚动UIPageViewController的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试设置一个 UIPageViewController ,它可以通过 NSUrlConnection 数据动态加载页面视图来无限滚动拉。我从3个观点开始:prev,curr,next;并在达到 pageData 数组中的第一个或最后一个视图时加载其他视图。

I'm trying to setup a UIPageViewController that can scroll infinitely by dynamically loading page views via an NSUrlConnection data pull. I start with 3 views: prev,curr,next; and load an additional view when the first or last view in the pageData array is reached.

问题是我在 viewControllerBeforeViewController viewControllerAfterViewController 。在页面之间进行单次滑动时,似乎可以调用这些方法2-3次。它们也可以在从不完成页面转换的半滑动期间调用。这可能意味着多个预加载开始过早完成。然后以某种方式 pageViewController 忘记当前位置。

The trouble is that I load the additional views in viewControllerBeforeViewController or viewControllerAfterViewController. It seems that these methods can be called 2-3 times when doing a single swipe between pages. They can also be called during a half-swipe that never finishes the page transition. This can mean that multiple preloads start getting done prematurely. Then somehow the pageViewController forgets the current location.

[self.pageViewController setViewControllers:@[[self.pageData objectAtIndex:gotoIdx]] direction:direction animated:NO completion:nil];

此行用于表示 pageViewController中的数据添加,并转到适当的视图。当我开始使用它时,它不是通过滑动进入上一个/下一个视图,而是开始跳转到看似随机的视图。一旦我开始向后滑动...

This line is used below to signal an addition of data in the pageViewController, and to go to eh appropriate view. When I start using it, instead of going to the prev/next view with a swipe, it starts jumping to seemingly random views. Once I started going forward when swiping backwards...

是否有更合适的地方进行预加载,仅在页面转换完成后调用一次?并且,是否必须调用上面的行,或者是否有更可靠的方法来确保它进入正确的页面?感觉很沮丧试图在这里连线。

Is there a more appropriate place to do the preload that is only called once after the page transition completes? And, does the line above have to be called, or is there a more reliable way to ensure it goes to the correct page? Feeling frustrated trying to wire this up here.

 // the init line, somewhere early on.  uses Scoll style
 self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationVertical options:nil];

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    NSUInteger index = [self.pageData indexOfObject:viewController];
    if(index == 1){
        // if loading last one on start, preload one more in advance
        [self loadSecondaryCalData:-1 endView:[[self viewControllerAtIndex:index-1] retain]];
    } else if ((index == 0) || (index == NSNotFound)) {
        return nil;
    }

    index--;
    return [self viewControllerAtIndex:index];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {

    NSUInteger index = [self.pageData indexOfObject:viewController];
    if(index == [self.pageData count]-2){
        [self loadSecondaryCalData:1 endView:[[self viewControllerAtIndex:index+1] retain]];  // if last one, preload one more in advance
    } else if (index == NSNotFound) {
        return nil;
    }

    index++;
    if (index == [self.pageData count]) {
        return nil;
    }
    return [self viewControllerAtIndex:index];
}


- (void)loadSecondaryCalData:(int)howMany endView:(CalendarViewController*)endView {
   // initiate NSURLConnection async request for view data
}

- (void)loadSecondaryCals: (NSDictionary*)data {
   // callback for async request

   // ... process view, cal

   // add new object to page data, at start or end
   if(next){
        [self.pageData addObject:cal];
        gotoIdx = [self.pageData count]-2;
        direction = UIPageViewControllerNavigationDirectionForward;
   } else {
        [self.pageData insertObject:cal atIndex:0];
        gotoIdx = 1;
        direction = UIPageViewControllerNavigationDirectionReverse;
   }

  [self.pageViewController setViewControllers:@[[self.pageData objectAtIndex:gotoIdx]] direction:direction animated:NO completion:nil];

// alternate method to above line
/*
__block CalendarPageViewViewController *blocksafeSelf = self;
__block int blocksafeGotoIdx = gotoIdx;
__block UIPageViewControllerNavigationDirection blocksafeDirection = direction;
[self.pageViewController setViewControllers:@[[self.pageData objectAtIndex:gotoIdx]] direction:direction animated:YES completion:^(BOOL finished){
    if(finished)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            [blocksafeSelf.pageViewController setViewControllers:@[[blocksafeSelf.pageData objectAtIndex:blocksafeGotoIdx]] direction:blocksafeDirection animated:NO completion:nil];
        });
    }
}];
*/


}

更新:

由于下面的快速响应,引用了一个我不知道的强大功能。这是预加载方法,只有在完成转换时才能完美地调用一次。这似乎已经大大消除了不可靠的跳跃视图和忘记位置。谢谢@sha!

Thanks to the fast response below, referencing a great function I wasn't aware of. Here's the preload method that so perfectly only gets called once on completion of the transition. This seems to have greatly cleared up the unreliable jumping around of views and forgetting of location. Thanks @sha!

// function to detect if we've reached the first or last item in views
// detects for full completion only
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {

    if(completed == TRUE && [previousViewControllers count] > 0 && [pageData count] > 1){
        CalendarViewController *firstCal = [pageData objectAtIndex:0];
        CalendarViewController *lastCal = [pageData objectAtIndex:([pageData count]-1)];

        CalendarViewController *prevCal = [previousViewControllers objectAtIndex:0];
        CalendarViewController *currCal = [[pageViewController viewControllers] objectAtIndex:0];

        NSLog(@"transition completed: %@ -> %@", prevCal.week_day_date, currCal.week_day_date);
        if(currCal == firstCal){
            // preload on begining
            [self loadSecondaryCalData:-1 endView:firstCal];
        } else if(currCal == lastCal){
            // preload to end
            [self loadSecondaryCalData:1 endView:lastCal];
        }
    }
}


推荐答案

我认为您需要在 pageViewController中执行加载调用:didFinishAnimating:previousViewControllers:transitionCompleted: handler。当动画完成并且新的ViewController成为活动的时,将调用此方法。

I think you need to do your loading calls inside pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted: handler. This method will be called when animation has finished and new ViewController became an active one.

这篇关于无限滚动UIPageViewController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-16 04:28