I am trying to modify Apple’s PhotoScroller example and I encountered a problem that I couldn’t solve.
Basically, the PhotoScroller originally loaded a bunch of image in an array locally. I try to modify this and change to it request an image file dynamically from an URL. Once the user scroll to the next page, it will fetch the next image from a new URL.
In order to improve the performance, I wanted to preload the next page so user doesn’t need to wait for the image being downloaded while scrolling to the next page. Once the next page is on current page, the page after that will be loaded and so on…
I’m not quite sure how I can achieve this and I hope someone can show me what to do.
Here is my custom code: (Please refer the full code from Apple’s PhotoScroller example)
tilePage method: (It will be call at the beginning and every time when user did scroll the scrollView)
- (void)tilePages
{
// Calculate which pages are visible
CGRect visibleBounds = pagingScrollView.bounds;
int firstNeededPageIndex = floorf(CGRectGetMinX(visibleBounds) / CGRectGetWidth(visibleBounds));
int lastNeededPageIndex = floorf((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds));
firstNeededPageIndex = MAX(firstNeededPageIndex, 0);
lastNeededPageIndex = MIN(lastNeededPageIndex, [self imageCount] - 1);
// Recycle no-longer-visible pages
for (ImageScrollView *page in visiblePages) {
if (page.index < firstNeededPageIndex || page.index > lastNeededPageIndex) {
[recycledPages addObject:page];
[page removeFromSuperview];
}
}
[visiblePages minusSet:recycledPages];
// add missing pages
for (int index = firstNeededPageIndex; index <= lastNeededPageIndex; index++) {
if (![self isDisplayingPageForIndex:index]) {
ImageScrollView *page = [self dequeueRecycledPage];
//ImageScrollView *nextpage = [self dequeueRecycledPage];
if (page == nil) {
page = [[[ImageScrollView alloc] init] autorelease];
}
[self configurePage:page forIndex:index];
[pagingScrollView addSubview:page];
[visiblePages addObject:page];
}
}
}
To configure page index and content:
- (void)configurePage:(ImageScrollView *)page forIndex:(NSUInteger)index
{
//set page index
page.index = index;
//set page frame
page.frame = [self frameForPageAtIndex:index];
//Actual method to call image to display
[page displayImage:[self imageAtIndex:index]];
NSLog(@"index: %i", index);
}
To fetch image from URL:
- (UIImage *)imageAtIndex:(NSUInteger)index {
NSString *string1 = [NSString stringWithString:@"http://abc.com/00"];
NSString *string2 = [NSString stringWithFormat:@"%d",index+1];
NSString *string3 = [NSString stringWithString:@".jpg"];
NSString *finalString = [NSString stringWithFormat:@"%@%@%@",string1,string2,string3];
NSLog(@"final string is: %@", finalString);
NSURL *imgURL = [NSURL URLWithString: finalString];
NSData *imgData = [NSData dataWithContentsOfURL:imgURL];
return [UIImage imageWithData:imgData];
}
Thanks for helping!
Lawrence
You can use concurrent operations to fetch images one after another. Using NSOperations, you can set a dependency chain so images are loaded in a serial fashion in the background, or you can have them all downloaded concurrently.
The problem with large images is that even though you save them in the file system, there is a “startup” time to get the images rendered. Also, in PhotoScroller, Apple “cheats” by having all the images pre tiled for each level of detail. Apple provides no way to render just a Plain ole JPEG in PhotoScroller, so unless you can pre tile it will be of no use to you.
If you are curious, you can see how to both download multiple images and pre tile them into a temporary file by perusing the PhotoScrollerNetwork project on github.