具有延迟加载的分页UIScrollview

时间:2011-07-24 19:53:43

标签: iphone ios uiscrollview

我需要有关uiscrollview实现的帮助,并满足以下要求:

1)pagingEnabled = true。
2)懒人页面加载。
3)页面在后台加载。所以我首先需要加载页面X,然后获得页面完全加载的通知,然后只允许用户滚动到它。
4)能够改变当前页面。

我的第一次尝试是覆盖scrollViewDidEndDeacelerating和scrollViewDidScroll,但是我遇到了一半页面上的问题(当你停止页面一半的滚动然后等待新页面添加到滚动时)并清空页面(当用户滚动太快时)。

我的第二次尝试是覆盖UIScrollView的layoutSubviews方法并在那里进行所有计算。但它似乎非常软化。

所以,我很想找到类似实现的任何例子。

现在我有这样的代码:

我已经实现了 scrollViewWillBeginDragging scrollViewDidEndDecelerating

- (void)scrollViewWillBeginDragging:(UIScrollView *)aScrollView
{
    isScrolling = YES;
} 
- (void)scrollViewDidEndDecelerating:(UIScrollView *)aScrollView
{
   isScrolling = NO;
   // Here we load the page that was prepared when the user was scrolling
  if (needDisplay > -1) {
        //NSLog(@"Loading queued page %d", needDisplay);
        [self loadScrollViewWithPage:needDisplay forceAddToSuperview:NO animated:YES];
        needDisplay = -1;
  }

  // minLoadedPageIndex - index of the first loaded page.
  int selectedIndex = MIN(floor((aScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1 + minLoadedPageIndex, [photoItems count] - 1); 

    [self loadScrollViewWithPage:selectedIndex - 1 forceAddToSuperview:NO animated:YES];
    [self loadScrollViewWithPage:selectedIndex forceAddToSuperview:NO animated:YES];
    [self loadScrollViewWithPage:selectedIndex + 1 forceAddToSuperview:NO animated:YES];
}

loadScrollViewWithPage 中,我创建了一个页面视图控制器,它在后台从服务器加载数据。在从服务器加载数据之前,我不会将视图添加到scrollview。

- (void)loadScrollViewWithPage:(int)page forceAddToSuperview:(BOOL)value animated:(BOOL)animated
{
    DetailController *controller = page >= viewControllers.count ? [NSNull null] :[viewControllers objectAtIndex:page];

    if ((NSNull *)controller == [NSNull null])
    {
        controller = [[DetailController alloc] initWithNibName:@"DetailController" bundle:nil];        
        controller.delegate = self;
        controller.view.hidden = NO; //this will call viewDidLoad.

        if (page >= viewControllers.count) {
            [viewControllers addObject:controller];
        }
        else {
            [viewControllers replaceObjectAtIndex:page withObject:controller];
        }

        [controller release];
    }

    // add the controller's view to the scroll view
    if (controller.view && controller.view.superview == nil && (controller.isLoadedOrFailed || value)) {
        [self setNumberOfVisiblePages:visiblePagesCount+1];  

        if (page < selectedIndex) {
           // We are adding the page to the left of the current page,
     // so we need to adjust the content offset.
            CGFloat offset = (int)scrollView.contentOffset.x % (int)scrollView.frame.size.width;
            offset = scrollView.frame.size.width * (selectedIndex - minLoadedPageIndex) + offset;
            [scrollView setContentOffset:CGPointMake(offset, 0.0) animated:animated];       
        }

        CGRect frame = scrollView.frame;
        frame.origin.x = frame.size.width * (page - minLoadedPageIndex);
        frame.origin.y = 0;
        controller.view.frame = frame;        
        [scrollView addSubview:controller.view];
        [controller viewWillAppear:NO];
    }
}

此外,我还有一个 detailControllerDidFinishDownload 方法,该方法在加载页面视图控制器的数据时调用。

- (void)detailControllerDidFinishDownload:(DetailController *)controller
{

  ... //here I calculate new minLoadedPageIndex value

 // reset pages frames
 if (minLoadedPageIndex < oldMinPage) {
        for(int i=oldMinPage;i < [viewControllers count]; i++) {
            DetailController *detailsController = [viewControllers objectAtIndex:i];
            if ((NSNull *)detailsController != [NSNull null]) {
                CGRect frame = scrollView.frame;
                frame.origin.x = frame.size.width * (i - minLoadedPageIndex);
                frame.origin.y = 0;

                [detailsController.view setFrame:frame];
            }
        }
    }

   // load the page now or delay load until the scrolling will be finished
   if (!isScrolling) {
        [self loadScrollViewWithPage:[photoItems indexOfObject:controller.photoItem] forceAddToSuperview:NO animated:NO];
    }
    else {
        needDisplay = [photoItems indexOfObject:controller.photoItem];
        //NSLog(@"pageControlUsed is used!!! %d", [photoItems indexOfObject:controller.photoItem]);
    }
}

我现在遇到的问题是,有时滚动卡在页面的中间(或接近中间的某个位置),它不会到达最近的页面反弹,直到我稍微多一点。我的测试显示,如果我滚出内容视图框(滚动视图已弹回)并等待加载新页面,则会出现这种情况。滚动卡在10次中的1次。

谢谢,米哈伊尔!

1 个答案:

答案 0 :(得分:1)

你需要同时做很多事情。我建议你看看这个例子。

http://ykyuen.wordpress.com/2010/05/22/iphone-uiscrollview-with-paging-example/

这是一个非常好的起点。