I have a UIView with 8 to 10 large images (each loaded in a UIImageView) as subzones. These images are aligned next to each other so that they constitute a real long horizontal image. This view is placed in a UIScrollView so that the user can scroll along this long horizontal image.
Downloading all of these images (from the Internet) takes quite a while, so I decided to put this download code in a subclass of NSOperation. Inside the main operation method, each ImageView is added to the container view.
In this process, the view is hidden, and instead a small rotating image appears (almost similar to the UIActivityIndicatorView). Here is the code:
CategoryViewController.m
- (id)initWithFrame:(CGRect)frame
{
self = [super init];
if(self)
{
[...]
loadIndicator = [[UIImageView alloc] initWithImage:img];
[loadIndicator setFrame:CGRectMake((frame.size.width - width) / 2, (frame.size.height - height) / 2, width, height)];
[loadIndicator setHidden:YES];
backgroundView = [[UIView alloc] init];
backgroundView.hidden = YES;
scrollView = [[UIScrollView alloc] initWithFrame:frame];
[scrollView setDelegate:(id<UIScrollViewDelegate>)self];
[scrollView addSubview:backgroundView];
[self.view setFrame:frame];
}
return self;
}
- (void)viewDidLoad
{
[...]
[self.view addSubview:loadIndicator];
[self.view addSubview:scrollView];
loadIndicator.hidden = NO;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
loadIndicatorRotation = 0;
rotationTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector:@selector(updateRotation:) userInfo: nil repeats: YES];
[UIView commitAnimations];
operationQueue = [[NSOperationQueue alloc] init];
LoadBackgroundImagesOperation* operation = [[LoadBackgroundImagesOperation alloc] initWithImages:bgImageNames View:backgroundView Frame:frame];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onFinishedLoadingBgImages) name:@"BgImagesFinishedLoading" object:operation];
[operationQueue addOperation:operation];
[operation release];
[super viewDidLoad];
}
Main method LoadBackgroundImagesOperation.m
- (void)main
{
int left = 0;
int width, height;
int i;
for(i = 0; i < imageNames.count; i++)
{
if([self isCancelled])
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"BgImagesCancelled" object:self];
return;
}
[...]
NSData* data = [[NSData alloc] initWithContentsOfURL:imgURL];
UIImage* image = [[UIImage alloc] initWithData:data];
[data release];
double scalingFactor = frame.size.height / image.size.height;
width = image.size.width * scalingFactor;
height = image.size.height * scalingFactor;
UIImageView* imgView = [[UIImageView alloc] initWithImage:image];
[image release];
[imgView setFrame:CGRectMake(left, 0, width, height)];
[background addSubview:imgView];
[imgView release];
left += width;
[background setFrame:CGRectMake(0, 0, left, height)];
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"BgImagesFinishedLoading" object:self];
}
When the operation is completed, I hide the rotating image and show a view containing large images.
(again in CategoryViewController.m)
- (void) onFinishedLoadingBgImages
{
[scrollView setContentSize:backgroundView.frame.size];
backgroundView.hidden = NO;
loadIndicator.hidden = YES;
if(operationQueue != nil)
{
[operationQueue cancelAllOperations];
[operationQueue release];
operationQueue = nil;
}
[rotationTimer invalidate];
rotationTimer = nil;
}
The problem is that the simulator takes about 2 seconds and up to 5 seconds on a real device until the images are really visible after the call backgroundView.hidden = NO
I would just keep showing an activity indicator for this time, but I don’t know how to detect what backgroundviewappeared to hide the indicator again.
backgroundview UIViewController viewDidAppear, . ( , viewDidAppear, , , ).
, backgroundview loadIndicator, , , .
, , , , backgroundview .
,
, , - . , .