iOS: Est-il un moyen de déterminer quand une UIView apparaître, après l'appel de la vue.hidden = PAS de
J'ai une UIView avec 8 à 10 grandes images (chaque chargé dans une UIImageView) comme des sous-vues. Ces images sont alignées les unes à côté des autres, de sorte qu'ils composent un vrai long horizontale de l'image. Ce point de vue est placé dans un UIScrollView, de sorte que l'utilisateur peut faire défiler le long de cette longue horizontale de l'image.
Le chargement de toutes les images (sur le web) prend du temps, j'ai donc décidé de mettre que le code de chargement dans un NSOperation sous-classe. À l'intérieur de l'opération principale de la méthode chaque ImageView est ajouté au conteneur de vue.
La vue est cachée pendant ce processus, et à la place il y a une petite rotation de l'image (un peu comme un UIActivityIndicatorView). Voici un code:
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];
}
principale méthode 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];
}
Lorsque l'opération est terminée, je me cache dans la rotation de l'image et de montrer le point de vue, qui contient les images de grande taille.
(de retour dans CategoryViewController.m nouveau)
- (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;
}
Le problème est que cela prend environ 2 secondes pour que le simulateur et jusqu'à 5 secondes sur le réel de l'appareil jusqu'à ce que les images sont vraiment visibles après l'appel de backgroundView.hidden = NO
Je vais simplement continuer à montrer l'indicateur d'activité pendant cette période, mais je ne sais pas comment faire pour détecter backgroundview
n'apparaissent dans l'ordre pour masquer l'indicateur de nouveau.
J'ai essayé de mettre backgroundview
dans son propre UIViewController et avertir mes parents-vue-contrôleur lorsque viewDidAppear est appelé, mais qui ne fonctionne pas. (J'ai lu que dans les contrôleurs de vue que je devrais l'appeler viewDidAppear manuellement, mais ce n'est pas une option, parce que je ne sais pas quand il est apparu dans la première place).
Aussi, je ne peux pas juste faire le sale truc et modifier l'ordre de backgroundView
et loadIndicator
de le cacher, parce que la plupart des images ont une certaine transparence en eux, de sorte que l'utilisateur puisse toujours voir l'indicateur.
Donc j'espère vraiment que l'un de vous les gars avez des suggestions sur la façon de détecter quand backgroundview
est réellement visible.
Grâce,
Chris
Oh, et désolé si le code est un peu sans rapport avec le problème. Voulais juste vous donner une vue d'ensemble de ce que je fais.
OriginalL'auteur christoph | 2011-05-31
Vous devez vous connecter pour publier un commentaire.
Ce que vous pourriez faire est de faire une sous-classe UIViewController, et de faire que le propriétaire de ce point de vue, et dans la méthode, vous pouvez essayer de mettre le code dans la méthode viewDidLoad et voir si c'est plus précis, mais je pense que la vraie question est la imageViews vous utilisez prennent leurs temps de chargement des images, pas le UIView. Par conséquent, la UIView est visible, cependant la imageViews n'ont pas chargé leurs images encore si vous ne voyez pas de quoi que ce soit.
OriginalL'auteur Chance Hudson
Si vous êtes à montrer beaucoup de grandes images dans l'un de défilement de la vue, vous devriez vraiment envisager de carrelage de sorte que des parties de l'image peuvent être chargées séparément et vous n'avez pas à garder plusieurs grandes images dans la mémoire de tous en même temps. Jetez un oeil à CATiledLayer et la PhotoScroller exemple de code.
OriginalL'auteur Caleb