Je veux lister toutes les sous-vues dans un fichier UIViewController
. J'ai essayé self.view.subviews
, mais toutes les sous-vues ne sont pas répertoriées, par exemple, les sous-vues de UITableViewCell
ne sont pas trouvées. Une idée?
ios
uiview
subview
uiview-hierarchy
utilisateur403015
la source
la source
Réponses:
Vous devez itérer récursivement les sous-vues.
- (void)listSubviewsOfView:(UIView *)view { // Get the subviews of the view NSArray *subviews = [view subviews]; // Return if there are no subviews if ([subviews count] == 0) return; // COUNT CHECK LINE for (UIView *subview in subviews) { // Do what you want to do with the subview NSLog(@"%@", subview); // List the subviews of subview [self listSubviewsOfView:subview]; } }
Comme l'a commenté @Greg Meletic, vous pouvez ignorer la COUNT CHECK LINE ci-dessus.
la source
recursiveDescription
réponse beaucoup plus simple de @natbro - stackoverflow.com/a/8962824/429521La méthode intégrée xcode / gdb pour vider la hiérarchie des vues est utile - recursiveDescription, par http://developer.apple.com/library/ios/#technotes/tn2239/_index.html
Il génère une hiérarchie de vues plus complète que vous pourriez trouver utile:
> po [_myToolbar recursiveDescription] <UIToolbarButton: 0xd866040; frame = (152 0; 15 44); opaque = NO; layer = <CALayer: 0xd864230>> | <UISwappableImageView: 0xd8660f0; frame = (0 0; 0 0); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0xd86a160>>
la source
[_myToolbar recursiveDescription]
dans mon code ou ailleurs.Solution récursive élégante dans Swift:
extension UIView { func subviewsRecursive() -> [UIView] { return subviews + subviews.flatMap { $0.subviewsRecursive() } } }
Vous pouvez appeler subviewsRecursive () sur n'importe quel UIView:
let allSubviews = self.view.subviewsRecursive()
la source
Vous devez imprimer de manière récursive, cette méthode utilise également des onglets en fonction de la profondeur de la vue
-(void) printAllChildrenOfView:(UIView*) node depth:(int) d { //Tabs are just for formatting NSString *tabs = @""; for (int i = 0; i < d; i++) { tabs = [tabs stringByAppendingFormat:@"\t"]; } NSLog(@"%@%@", tabs, node); d++; //Increment the depth for (UIView *child in node.subviews) { [self printAllChildrenOfView:child depth:d]; } }
la source
Voici la version rapide
func listSubviewsOfView(view:UIView){ // Get the subviews of the view var subviews = view.subviews // Return if there are no subviews if subviews.count == 0 { return } for subview : AnyObject in subviews{ // Do what you want to do with the subview println(subview) // List the subviews of subview listSubviewsOfView(subview as UIView) } }
la source
Je suis un peu en retard à la fête, mais solution un peu plus générale:
@implementation UIView (childViews) - (NSArray*) allSubviews { __block NSArray* allSubviews = [NSArray arrayWithObject:self]; [self.subviews enumerateObjectsUsingBlock:^( UIView* view, NSUInteger idx, BOOL*stop) { allSubviews = [allSubviews arrayByAddingObjectsFromArray:[view allSubviews]]; }]; return allSubviews; } @end
la source
Si tout ce que vous voulez est un tableau de
UIView
s, c'est une solution à une seule ligne ( Swift 4+ ):extension UIView { var allSubviews: [UIView] { return self.subviews.reduce([UIView]()) { $0 + [$1] + $1.allSubviews } } }
la source
J'utilise de cette façon:
NSLog(@"%@", [self.view subviews]);
dans le UIViewController.
la source
Détails
Solution
extension UIView { private func subviews(parentView: UIView, level: Int = 0, printSubviews: Bool = false) -> [UIView] { var result = [UIView]() if level == 0 && printSubviews { result.append(parentView) print("\(parentView.viewInfo)") } for subview in parentView.subviews { if printSubviews { print("\(String(repeating: "-", count: level))\(subview.viewInfo)") } result.append(subview) if subview.subviews.isEmpty { continue } result += subviews(parentView: subview, level: level+1, printSubviews: printSubviews) } return result } private var viewInfo: String { return "\(classForCoder), frame: \(frame))" } var allSubviews: [UIView] { return subviews(parentView: self) } func printSubviews() { _ = subviews(parentView: self, printSubviews: true) } }
Usage
view.printSubviews() print("\(view.allSubviews.count)")
Résultat
la source
À ma manière, la catégorie ou l'extension d'UIView est bien meilleure que les autres et récursive est le point clé pour obtenir toutes les sous-vues
apprendre encore plus:
https://github.com/ZhipingYang/XYDebugView
Objectif c
@implementation UIView (Recurrence) - (NSArray<UIView *> *)recurrenceAllSubviews { NSMutableArray <UIView *> *all = @[].mutableCopy; void (^getSubViewsBlock)(UIView *current) = ^(UIView *current){ [all addObject:current]; for (UIView *sub in current.subviews) { [all addObjectsFromArray:[sub recurrenceAllSubviews]]; } }; getSubViewsBlock(self); return [NSArray arrayWithArray:all]; } @end
exemple
NSArray *views = [viewController.view recurrenceAllSubviews];
Swift 3.1
extension UIView { func recurrenceAllSubviews() -> [UIView] { var all = [UIView]() func getSubview(view: UIView) { all.append(view) guard view.subviews.count>0 else { return } view.subviews.forEach{ getSubview(view: $0) } } getSubview(view: self) return all } }
exemple
let views = viewController.view.recurrenceAllSubviews()
directement, utilisez la fonction de séquence pour obtenir toutes les sous-vues
let viewSequence = sequence(state: [viewController.view]) { (state: inout [UIView] ) -> [UIView]? in guard state.count > 0 else { return nil } defer { state = state.map{ $0.subviews }.flatMap{ $0 } } return state } let views = viewSequence.flatMap{ $0 }
la source
La raison pour laquelle les sous-vues dans un UITableViewCell ne sont pas imprimées est que vous devez générer toutes les sous-vues du niveau supérieur. Les sous-vues de la cellule ne sont pas les sous-vues directes de votre vue.
Afin d'obtenir les sous-vues de UITableViewCell, vous devez déterminer les sous-vues appartenant à un UITableViewCell (en utilisant
isKindOfClass:
) dans votre boucle d'impression, puis parcourez ses sous-vues.Edit: Ce billet de blog sur le débogage Easy UIView peut potentiellement aider
la source
J'ai écrit une catégorie pour répertorier toutes les vues détenues par un contrôleur de vue inspiré des réponses publiées auparavant.
@interface UIView (ListSubviewHierarchy) - (NSString *)listOfSubviews; @end @implementation UIView (ListSubviewHierarchy) - (NSInteger)depth { NSInteger depth = 0; if ([self superview]) { deepth = [[self superview] depth] + 1; } return depth; } - (NSString *)listOfSubviews { NSString * indent = @""; NSInteger depth = [self depth]; for (int counter = 0; counter < depth; counter ++) { indent = [indent stringByAppendingString:@" "]; } __block NSString * listOfSubviews = [NSString stringWithFormat:@"\n%@%@", indent, [self description]; if ([self.subviews count] > 0) { [self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { UIView * subview = obj; listOfSubviews = [listOfSubviews stringByAppendingFormat:@"%@", [subview listOfSubviews]]; }]; } return listOfSubviews; } @end
Pour lister toutes les vues détenues par un contrôleur de vue, juste
NSLog("%@",[self listOfSubviews])
, ce quiself
signifie le contrôleur de vue lui-même. Bien que ce ne soit pas efficace.De plus, vous pouvez utiliser
NSLog(@"\n%@", [(id)self.view performSelector:@selector(recursiveDescription)]);
pour faire la même chose, et je pense que c'est plus efficace que ma mise en œuvre.la source
Exemple simple de Swift:
var arrOfSub = self.view.subviews print("Number of Subviews: \(arrOfSub.count)") for item in arrOfSub { print(item) }
la source
Vous pouvez essayer une astuce de tableau sophistiquée, comme:
[self.view.subviews makeObjectsPerformSelector: @selector(printAllChildrenOfView)];
Juste une ligne de code. Bien sûr, vous devrez peut-être ajuster votre méthode
printAllChildrenOfView
pour ne prendre aucun paramètre ou créer une nouvelle méthode.la source
Compatible Swift 2.0
Voici une méthode récursive pour obtenir toutes les sous-vues d'une vue générique:
extension UIView { func subviewsList() -> [UIView] { var subviews = self.subviews if subviews.count == 0 { return subviews + [] } for v in subviews { subviews += v.listSubviewsOfView() } return subviews } }
Ainsi, vous pouvez appeler partout de cette manière:
let view = FooController.view let subviews = view.subviewsList()
la source
Solution la plus courte
for subview in self.view.subviews { print(subview.dynamicType) }
Résultat
UIView UIView UISlider UISwitch UITextField _UILayoutGuide _UILayoutGuide
Remarques
la source
C'est une réécriture de ceci réponse:
Vous devez d'abord obtenir le pointeur / la référence de l'objet que vous souhaitez imprimer toutes ses sous-vues. Parfois, vous pouvez trouver plus facile de trouver cet objet en y accédant via sa sous-vue. Comme
po someSubview.superview
. Cela vous donnera quelque chose comme:Optional<UIView> ▿ some : <FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
superview
0x7f91747c71f0
est le pointeur vers le superview.Pour imprimer le superView, vous devez utiliser des points d'arrêt.
Maintenant, pour faire cette étape, vous pouvez simplement cliquer sur «Afficher la hiérarchie de débogage». Pas besoin de points d'arrêt
Ensuite, vous pouvez facilement faire:
po [0x7f91747c71f0 recursiveDescription]
qui pour moi a renvoyé quelque chose comme:
<FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>> | <UIStackView: 0x7f91747c75f0; frame = (45 60; 264 93); layer = <CATransformLayer: 0x610000230ec0>> | | <UIImageView: 0x7f916ef38c30; frame = (10.6667 0; 243 58); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x61000003b840>> | | <UIStackView: 0x7f91747c8230; frame = (44.6667 58; 174.667 35); layer = <CATransformLayer: 0x6100006278c0>> | | | <FacebookApp.CopyableUILabel: 0x7f91747a80b0; baseClass = UILabel; frame = (44 0; 86.6667 16); text = 'What's New'; gestureRecognizers = <NSArray: 0x610000c4a770>; layer = <_UILabelLayer: 0x610000085550>> | | | <FacebookApp.CopyableUILabel: 0x7f916ef396a0; baseClass = UILabel; frame = (0 21; 174.667 14); text = 'Version 14.0.5c Oct 05, 2...'; gestureRecognizers = <NSArray: 0x610000c498a0>; layer = <_UILabelLayer: 0x610000087300>> | <UITextView: 0x7f917015ce00; frame = (45 183; 264 403); text = ' • new Adding new feature...'; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x6100000538f0>; layer = <CALayer: 0x61000042f000>; contentOffset: {0, 0}; contentSize: {264, 890}> | | <<_UITextContainerView: 0x7f9170a13350; frame = (0 0; 264 890); layer = <_UITextTiledLayer: 0x6080002c0930>> minSize = {0, 0}, maxSize = {1.7976931348623157e+308, 1.7976931348623157e+308}, textContainer = <NSTextContainer: 0x610000117b20 size = (264.000000,340282346638528859811704183484516925440.000000); widthTracksTextView = YES; heightTracksTextView = NO>; exclusionPaths = 0x61000001bc30; lineBreakMode = 0> | | | <_UITileLayer: 0x60800023f8a0> (layer) | | | <_UITileLayer: 0x60800023f3c0> (layer) | | | <_UITileLayer: 0x60800023f360> (layer) | | | <_UITileLayer: 0x60800023eca0> (layer) | | <UIImageView: 0x7f9170a7d370; frame = (-39 397.667; 36 2.33333); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x60800023f4c0>> | | <UIImageView: 0x7f9170a7d560; frame = (258.667 -39; 2.33333 36); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x60800023f5e0>> | <UIView: 0x7f916ef149c0; frame = (0 587; 354 0); layer = <CALayer: 0x6100006392a0>> | <UIButton: 0x7f91747a8730; frame = (0 0; 0 0); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x610000639320>> | | <UIButtonLabel: 0x7f916ef00a80; frame = (0 -5.66667; 0 16); text = 'See More Details'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x610000084d80>>
comme vous devez l'avoir deviné, ma supervision a 4 sous-vues:
C'est assez nouveau pour moi, mais cela m'a aidé à déboguer les cadres de mes vues (ainsi que le texte et le type). Une de mes sous-vues n'apparaissait pas à l'écran, alors j'ai utilisé recursiveDescription et j'ai réalisé que la largeur de l'une de mes sous-vues était
0
... alors j'ai corrigé ses contraintes et la sous-vue apparaissait.la source
Sinon, si vous souhaitez renvoyer un tableau de toutes les sous-vues (et sous-vues imbriquées) à partir d'une extension UIView:
func getAllSubviewsRecursively() -> [AnyObject] { var allSubviews: [AnyObject] = [] for subview in self.subviews { if let subview = subview as? UIView { allSubviews.append(subview) allSubviews = allSubviews + subview.getAllSubviewsRecursively() } } return allSubviews }
la source
Version AC # Xamarin:
void ListSubviewsOfView(UIView view) { var subviews = view.Subviews; if (subviews.Length == 0) return; foreach (var subView in subviews) { Console.WriteLine("Subview of type {0}", subView.GetType()); ListSubviewsOfView(subView); } }
Alternativement, si vous souhaitez trouver toutes les sous-vues d'un type spécifique que j'utilise:
List<T> FindViews<T>(UIView view) { List<T> allSubviews = new List<T>(); var subviews = view.Subviews.Where(x => x.GetType() == typeof(T)).ToList(); if (subviews.Count == 0) return allSubviews; foreach (var subView in subviews) { allSubviews.AddRange(FindViews<T>(subView)); } return allSubviews; }
la source
Je l'ai fait dans une catégorie d'
UIView
appeler simplement la fonction en passant l'index pour les imprimer avec un joli format d'arbre. Ceci est juste une autre option de la réponse publiée par James Webster .#pragma mark - Views Tree - (void)printSubviewsTreeWithIndex:(NSInteger)index { if (!self) { return; } NSString *tabSpace = @""; @autoreleasepool { for (NSInteger x = 0; x < index; x++) { tabSpace = [tabSpace stringByAppendingString:@"\t"]; } } NSLog(@"%@%@", tabSpace, self); if (!self.subviews) { return; } @autoreleasepool { for (UIView *subView in self.subviews) { [subView printViewsTreeWithIndex:index++]; } } }
J'espère que cela aide :)
la source
- (NSString *)recusiveDescription:(UIView *)view { NSString *s = @""; NSArray *subviews = [view subviews]; if ([subviews count] == 0) return @"no subviews"; for (UIView *subView in subviews) { s = [NSString stringWithFormat:@"<%@; frame = (%f %f : %f %f) \n ",NSStringFromClass([subView class]), subView.frame.origin.x, subView.frame.origin.y ,subView.frame.size.width, subView.frame.size.height]; [self recusiveDescription:subView]; } return s; }
la source
self.view.subviews maintient la hiérarchie des vues. Pour obtenir des sous-vues de uitableviewcell, vous devez faire quelque chose comme ci-dessous.
for (UIView *subView in self.view.subviews) { if ([subView isKindOfClass:[UITableView class]]) { for (UIView *tableSubview in subView.subviews) { ....... } } }
la source