Tengo una UIView con 8 a 10 imágenes de gran tamaño (cada carga en un UIImageView) como subvistas. Esas imágenes están alineados uno al lado del otro, a fin de que se redacte un largo horizontal de la imagen. Este punto de vista se pone en un UIScrollView, de modo que el usuario puede desplazarse a lo largo de este largo horizontal de la imagen.

La carga de todas las imágenes (de la web) toma bastante tiempo, así que me decidí a poner que cargar el código en un NSOperation subclase. Dentro de la operación método principal de cada ImageView se agrega al recipiente de vista.

La vista está oculta durante este proceso, y en su lugar hay una pequeña rotación de la imagen (casi tanto como un UIActivityIndicatorView). Aquí está el código:

CategoryViewController.m

- (id)initWithFrame:(CGRect)frame
{
self = [super init];
if(self)
{
//do some unrelated stuff
[...]
loadIndicator = [[UIImageView alloc] initWithImage:img];
[loadIndicator setFrame:CGRectMake((frame.size.width - width) / 2, (frame.size.height - height) / 2, width, height)];
[loadIndicator setHidden:YES];
//this is the view which will contain those large images
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
{
//do some unrelated stuff
[...]
[self.view addSubview:loadIndicator];
[self.view addSubview:scrollView];
//setup a custom activity indicator
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];
//setup the operation to load all background images
operationQueue = [[NSOperationQueue alloc] init];
LoadBackgroundImagesOperation* operation = [[LoadBackgroundImagesOperation alloc] initWithImages:bgImageNames View:backgroundView Frame:frame];
//register to recieve the finish notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onFinishedLoadingBgImages) name:@"BgImagesFinishedLoading" object:operation];
//Add the operation to the queue
[operationQueue addOperation:operation];
[operation release];
[super viewDidLoad];
}

principal método de 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;
}
//code to retrieve the url of current image
[...]
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];
}

Cuando la operación ha terminado puedo ocultar de la rotación de la imagen y mostrar la vista, que contiene las imágenes de gran tamaño.

(en CategoryViewController.m otra vez)

- (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;
}

El problema es que se tarda alrededor de 2 segundos para el simulador y hasta 5 segundos en el dispositivo real, hasta que las imágenes son realmente visibles después de llamar a backgroundView.hidden = NO

Sólo quiero que siga mostrando el indicador de actividad durante ese tiempo, pero no sé cómo detectar que backgroundview hizo aparecer en el fin de ocultar el indicador de nuevo.

Traté de poner backgroundview en su propio UIViewController y notificar a mi padre controlador de vista cuando viewDidAppear se llama, pero que no funciona. (He leído que en vista anidada controladores que tendría que llamar a viewDidAppear manualmente, pero esa no es una opción, porque no sé cuando apareció en el primer lugar).

También, no puedo hacer el truco sucio y cambiar el orden de backgroundView y loadIndicator de ocultarlo, porque la mayoría de las imágenes tienen un poco de transparencia en ellos, por lo que el usuario vea el indicador.

Así que realmente espero que alguno de ustedes tiene alguna sugerencia sobre cómo detectar cuando backgroundview es realmente visible.

Gracias,
Chris

Ah, y lo siento si algunos de los códigos es algo no relacionado con el problema. Sólo quería dar una idea general de lo que estoy haciendo.

InformationsquelleAutor christoph | 2011-05-31

2 Comentarios

  1. 2

    Lo que puede hacer es hacer un UIViewController subclase, y hacer que el propietario de este punto de vista, y en que el método podría tratar de poner el código que usted necesita en el método viewDidLoad y ver si eso es más preciso, sin embargo creo que el verdadero problema es el imageViews que utiliza están tomando su tiempo de carga de las imágenes, no el UIView. Por lo tanto, el UIView es visible, sin embargo, el imageViews no han cargado sus imágenes aún así no se ve nada.

    • Eso es lo que yo sospechaba. Pensé que tal vez hay una manera de determinar cuando el imageViews apareció, pero creo que no hay ninguno.
  2. 1

    Si usted está demostrando una gran cantidad de imágenes de gran tamaño en un desplazamiento de la vista, que realmente debería considerar mosaico de ellos, de modo que las partes de las imágenes se pueden cargar por separado y que usted no tiene que mantener varias imágenes de gran tamaño en la memoria, todo al mismo tiempo. Echa un vistazo a CATiledLayer y la PhotoScroller código de ejemplo.

    • Gracias por los enlaces a las muestras. Voy a comprobar a cabo.

Dejar respuesta

Please enter your comment!
Please enter your name here