UIScrollview:延迟加载 lazily load(动态加载)

分类:IOS    发布时间:2012/3/13 18:57:07

发现一篇很不错的文章

UIScrollview要加载大量数据的时候,考虑到内存的消耗问题,我们不可能全部加载完。

因此,需要找到个方法去延迟加载(lazily load)。参考官方例子:PageControl中的iphone页面。ipad的是popover弹窗的示例。

关于这个例子(我下的是1.4版的),运行会出现问题:[WARN]Warning: Multiple build commands for output file……png什么的。应该是图片加载不了。我搜索了下得到的答案是:http://stackoverflow.com/questions/2718246/xcode-strange-warning-multiple-build-commands-for-output-file

大概的问题在于资源文件冲突还是什么的,xcode识别不了。我把相关的ipad的东西先delete references,再运行还是出错。没办法,单步跟,居然一点问题都没有。。。。我了个去的。

算了反正是需要研究运行原理和看代码示例,我就刚好跟着学习下怎么延迟加载。

我习惯于在viewDidLoad中把已加载的nib文件再重画,而本官方例子(PageControl)在awakeFromNib中就搭好了框架。

awakeFromNib中,先画好scrollview的大小和里面的内容contentSize大小:

// view controllers are created lazily 将要加载的内容先置为空

// in the meantime, load the array with placeholders which will be replaced on demand

NSMutableArray *controllers = [[NSMutableArray alloc] init];

for (unsigned i = 0; i < kNumberOfPages; i++)

{

[controllers addObject:[NSNull null]];

}

self.viewControllers = controllers;

[controllers release];

// a page is the width of the scroll view

// 再将要加载的contentViewController的内容长度设定好

scrollView.pagingEnabled = YES;

scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);

scrollView.showsHorizontalScrollIndicator = NO;

scrollView.showsVerticalScrollIndicator = NO;

scrollView.scrollsToTop = NO;

scrollView.delegate = self;

pageControl.numberOfPages = kNumberOfPages;

pageControl.currentPage = 0;

// pages are created on demand

// load the visible page

// load the page on either side to avoid flashes when the user starts scrolling

// 然后先加载第一页和第二页

[self loadScrollViewWithPage:0];

[self loadScrollViewWithPage:1];

然后我们再跳转到loadScrollViewWithPage:这个方法(后面加载其他的页面都使用这个方法):

- (void)loadScrollViewWithPage:(int)page

{

// 判断内容页面是否到了第一或者最后一页

if (page < 0)

return;

if (page >= kNumberOfPages)

return;

// replace the  if necessary         加载scrollView里的该page内容页面,自定义的MyViewController

MyViewController *controller = [viewControllers objectAtIndex:page];

if ((NSNull *)controller == [NSNull null])

{

controller = [[MyViewController alloc] initWithPageNumber:page];//自定义的viewController初始方法

[viewControllers replaceObjectAtIndex:page withObject:controller];//替换之前内容置为空的相应页面

[controller release];

}

// add the controller’s view to the scroll view 将已替换的页面再加入到scrollView中显示

if (controller.view.superview == nil)

{

CGRect frame = scrollView.frame;//设定该page的frame

frame.origin.x = frame.size.width * page;

frame.origin.y = 0;

controller.view.frame = frame;

[scrollView addSubview:controller.view];

NSDictionary *numberItem = [self.contentList objectAtIndex:page];//加载一些自定义的内容

controller.numberImage.image = [UIImage imageNamed:[numberItem valueForKey:ImageKey]];

controller.numberTitle.text = [numberItem valueForKey:NameKey];

}

}

加载完成后再当前的scrollView。本例子中一个controller内的页面内容为一个scrollView

- (UIView *)view

{

return self.scrollView;

}

那么到这时候,我们就可以在屏幕上看到已经初始化好了的第一个页面了。然后就是到了我们在控制滑动scrollView的时候如何去 加载尚未初始化的其他页面了。

先看下面这2个方法,是实现scrollView的delegate方法。在scrollView滚动开始和结束的时候被调用。在这2个方法中我们用一个pageControlUsed的bool变量来控制是否加载新的页面

// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

{

pageControlUsed = NO;

}

// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

{

pageControlUsed = NO;

}

然后在滚动的过程中,scrollView的这个delegate方法被调用,我们在这个方法去设定加载的内容,然后再调用之前的loadScrollViewWithPage:去初始化和加载内容。

- (void)scrollViewDidScroll:(UIScrollView *)sender

{

// We don’t want a “feedback loop” between the UIPageControl and the scroll delegate in

// which a scroll event generated from the user hitting the page control triggers updates from

// the delegate method. We use a boolean to disable the delegate logic when the page control is used.

if (pageControlUsed)

{

// do nothing – the scroll was initiated from the page control, not the user dragging

return;

}

// Switch the indicator when more than 50% of the previous/next page is visible

// 控制在页面转到50%的时候设定加载新内容

CGFloat pageWidth = scrollView.frame.size.width;

int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;

pageControl.currentPage = page;

// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)

[self loadScrollViewWithPage:page - 1];

[self loadScrollViewWithPage:page];

[self loadScrollViewWithPage:page + 1];

// A possible optimization would be to unload the views+controllers which are no longer visible

// 这里就可以自己设定去释放那些没有加载的内容了

}


最新评论

我要发表评论

名称:
电子邮件:
个人主页:
内容:

 博客分类