Comment puis-je parcourir toutes les sous-vues d’un UIView, leurs sous-vues et leurs sous-vues

Comment puis-je parcourir toutes les sous-vues d’un UIView, leurs sous-vues et leurs sous-vues?

Utilisez la récursivité:

// UIView+HierarchyLogging.h @interface UIView (ViewHierarchyLogging) - (void)logViewHierarchy; @end // UIView+HierarchyLogging.m @implementation UIView (ViewHierarchyLogging) - (void)logViewHierarchy { NSLog(@"%@", self); for (UIView *subview in self.subviews) { [subview logViewHierarchy]; } } @end // In your implementation [myView logViewHierarchy]; 

Eh bien voici ma solution en utilisant récursivité et un wrapper (category / extension) pour la classe UIView.

 // UIView+viewRecursion.h @interface UIView (viewRecursion) - (NSMutableArray*) allSubViews; @end // UIView+viewRecursion.m @implementation UIView (viewRecursion) - (NSMutableArray*)allSubViews { NSMutableArray *arr=[[[NSMutableArray alloc] init] autorelease]; [arr addObject:self]; for (UIView *subview in self.subviews) { [arr addObjectsFromArray:(NSArray*)[subview allSubViews]]; } return arr; } @end 

Utilisation: vous devez maintenant parcourir toutes les sous-vues et les manipuler selon vos besoins.

 //disable all text fields for(UIView *v in [self.view allSubViews]) { if([v isKindOfClass:[UITextField class]]) { ((UITextField*)v).enabled=NO; } } 

Une solution dans Swift 3 qui donne toutes les sous- subviews sans inclure la vue elle-même:

 extension UIView { var allSubViews : [UIView] { var array = [self.subviews].flatMap {$0} array.forEach { array.append(contentsOf: $0.allSubViews) } return array } } 

Vous venez de trouver un moyen intéressant de le faire via le débogueur:

http://idevrecipes.com/2011/02/10/exploring-iphone-view-hierarchies/

fait référence à cette note technique Apple:

https://developer.apple.com/library/content/technotes/tn2239/_index.html#SECUIKIT

Assurez-vous simplement que votre débogueur est en pause (définissez un point d’arrêt de pause manuellement) et vous pouvez demander la recursiveDescription .

Je marque tout quand il est créé. Il est alors facile de trouver une sous-vue.

 view = [aView viewWithTag:tag]; 

Avec l’aide d’Ole Begemann. J’ai ajouté quelques lignes pour y incorporer le concept de bloc.

UIView + HierarchyLogging.h

 typedef void (^ViewActionBlock_t)(UIView *); @interface UIView (UIView_HierarchyLogging) - (void)logViewHierarchy: (ViewActionBlock_t)viewAction; @end 

UIView + HierarchyLogging.m

 @implementation UIView (UIView_HierarchyLogging) - (void)logViewHierarchy: (ViewActionBlock_t)viewAction { //view action block - freedom to the caller viewAction(self); for (UIView *subview in self.subviews) { [subview logViewHierarchy:viewAction]; } } @end 

Utiliser la catégorie HierarchyLogging dans votre ViewController. Vous êtes maintenant libre de ce que vous devez faire.

 void (^ViewActionBlock)(UIView *) = ^(UIView *view) { if ([view isKindOfClass:[UIButton class]]) { NSLog(@"%@", view); } }; [self.view logViewHierarchy: ViewActionBlock]; 

Voici un code récursif: –

  for (UIView *subViews in yourView.subviews) { [self removSubviews:subViews]; } -(void)removSubviews:(UIView *)subView { if (subView.subviews.count>0) { for (UIView *subViews in subView.subviews) { [self removSubviews:subViews]; } } else { NSLog(@"%i",subView.subviews.count); [subView removeFromSuperview]; } } 

Au fait, j’ai fait un projet open source pour aider avec ce genre de tâche. C’est très simple et utilise des blocs Objective-C 2.0 pour exécuter du code sur toutes les vues d’une hiérarchie.

https: //github.com/egold/UIViewRecursion

Exemple:

 -(void)makeAllSubviewsGreen { [self.view runBlockOnAllSubviews:^(UIView *view) { view.backgroundColor = [UIColor greenColor]; }]; } 

Vous n’avez pas besoin de créer de nouvelle fonction. Il suffit de le faire lors du débogage avec Xcode.

Définissez un point d’arrêt dans un contrôleur de vue et mettez l’application en pause à ce point d’arrêt.

Faites un clic droit sur la zone vide et appuyez sur “Ajouter une expression …” dans la fenêtre de surveillance de Xcode.

Entrez cette ligne:

 (NSSsortingng*)[self->_view recursiveDescription] 

Si la valeur est trop longue, faites un clic droit dessus et choisissez “Imprimer la description de …”. Vous verrez toutes les sous-vues de self.view dans la fenêtre de la console. Changer self -> _ view à autre chose si vous ne voulez pas voir les sous-vues de self.view.

Terminé! Non gdb!

Voici un exemple avec la fonctionnalité de bouclage et de rupture de vue.

 typedef void(^ViewBlock)(UIView* view, BOOL* stop); @interface UIView (ViewExtensions) -(void) loopViewHierarchy:(ViewBlock) block; @end @implementation UIView (ViewExtensions) -(void) loopViewHierarchy:(ViewBlock) block { BOOL stop = NO; if (block) { block(self, &stop); } if (!stop) { for (UIView* subview in self.subviews) { [subview loopViewHierarchy:block]; } } } @end 

Exemple d’appel:

 [mainView loopViewHierarchy:^(UIView* view, BOOL* stop) { if ([view isKindOfClass:[UIButton class]]) { /// use the view *stop = YES; } }]; 

Voici une variation de la réponse d’Ole Begemann ci-dessus, qui ajoute l’indentation pour illustrer la hiérarchie:

 // UIView+HierarchyLogging.h @interface UIView (ViewHierarchyLogging) - (void)logViewHierarchy:(NSSsortingng *)whiteSpaces; @end // UIView+HierarchyLogging.m @implementation UIView (ViewHierarchyLogging) - (void)logViewHierarchy:(NSSsortingng *)whiteSpaces { if (whiteSpaces == nil) { whiteSpaces = [NSSsortingng ssortingng]; } NSLog(@"%@%@", whiteSpaces, self); NSSsortingng *adjustedWhiteSpaces = [whiteSpaces ssortingngByAppendingFormat:@" "]; for (UIView *subview in self.subviews) { [subview logViewHierarchy:adjustedWhiteSpaces]; } } @end 

Le code publié dans cette réponse traverse toutes les fenêtres et toutes les vues et toutes leurs sous-vues. Il a été utilisé pour transférer une impression de la hiérarchie de vues vers NSLog, mais vous pouvez l’utiliser comme base pour toute traversée de la hiérarchie de vues. Il utilise une fonction C récursive pour parcourir l’arborescence.

Il y a quelque temps, j’ai écrit une catégorie pour déboguer des vues.

IIRC, le code affiché est celui qui a fonctionné. Sinon, cela vous orientera dans la bonne direction. Utiliser à vos risques, etc.

Cela affiche également le niveau de hiérarchie

 @implementation UIView (ViewHierarchyLogging) - (void)logViewHierarchy:(int)level { NSLog(@"%d - %@", level, self); for (UIView *subview in self.subviews) { [subview logViewHierarchy:(level+1)]; } } @end 

J’aurais aimé trouver cette page en premier, mais si (pour une raison quelconque) vous voulez le faire de manière non récursive, pas dans une catégorie et avec plus de lignes de code

Je pense que toutes les réponses utilisant la récursivité (à l’exception de l’option débogueur) ont utilisé des catégories. Si vous n’avez pas besoin d’une catégorie, vous pouvez simplement utiliser une méthode d’instance. Par exemple, si vous devez obtenir un tableau de toutes les étiquettes dans votre hiérarchie de vues, vous pouvez le faire.

 @interface MyViewController () @property (nonatomic, retain) NSMutableArray* labelsArray; @end @implementation MyViewController - (void)recursiveFindLabelsInView:(UIView*)inView { for (UIView *view in inView.subviews) { if([view isKindOfClass:[UILabel class]]) [self.labelsArray addObject: view]; else [self recursiveFindLabelsInView:view]; } } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.labelsArray = [[NSMutableArray alloc] init]; [self recursiveFindLabelsInView:self.view]; for (UILabel *lbl in self.labelsArray) { //Do something with labels } } 

Voici une autre implémentation de Swift:

 extension UIView { var allSubviews: [UIView] { return self.subviews.flatMap { [$0] + $0.allSubviews } } } 

La méthode ci-dessous crée un ou plusieurs tableaux modifiables, puis parcourt les sous-vues de la vue d’entrée. Ce faisant, il ajoute la sous-vue initiale puis demande s’il existe des sous-vues de cette sous-vue. Si c’est vrai, il s’appelle à nouveau. Il le fait jusqu’à ce que toutes les vues de la hiérarchie aient été ajoutées.

 -(NSArray *)allSubs:(UIView *)view { NSMutableArray * ma = [NSMutableArray new]; for (UIView * sub in view.subviews){ [ma addObject:sub]; if (sub.subviews){ [ma addObjectsFromArray:[self allSubs:sub]]; } } return ma; } 

Appeler en utilisant:

 NSArray * subviews = [self allSubs:someView];