Как перечислить все подпредставления в контроллере uiview в iOS? - PullRequest
83 голосов
/ 30 августа 2011

Я хочу перечислить все подпредставления в UIViewController. Я пробовал self.view.subviews, но не все подпредставления перечислены, например, подпредставления в UITableViewCell не найдены. Есть идеи?

Ответы [ 22 ]

2 голосов
/ 10 ноября 2012

Я написал категорию, чтобы вывести список всех представлений, поддерживаемых контроллером представлений, вдохновленный ответами, опубликованными ранее.

@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

Чтобы вывести список всех представлений, удерживаемых контроллером представлений, просто NSLog("%@",[self listOfSubviews]), что self означает сам контроллер вида.Хотя это не совсем эффективно.

Плюс, вы можете использовать NSLog(@"\n%@", [(id)self.view performSelector:@selector(recursiveDescription)]);, чтобы сделать то же самое, и я думаю, что это более эффективно, чем моя реализация.

2 голосов
/ 17 ноября 2014

Простой пример Swift:

 var arrOfSub = self.view.subviews
 print("Number of Subviews: \(arrOfSub.count)")
 for item in arrOfSub {
    print(item)
 }
2 голосов
/ 30 августа 2011

Причина, по которой подпредставления в UITableViewCell не распечатываются, заключается в том, что вы должны выводить все подпредставления на верхнем уровне.Подвиды ячейки не являются прямыми подпредставлениями вашей точки зрения.

Чтобы получить подпредставления UITableViewCell, вам необходимо определить, какие подпредставления принадлежат UITableViewCell (используя isKindOfClass:) в цикле печати, а затем выполнить цикл по его подпредставлениям

Редактировать: Этосообщение в блоге Easy UIView Отладка может потенциально помочь

1 голос
/ 30 августа 2011

Вы можете попробовать сложный трюк с массивами, например:

[self.view.subviews makeObjectsPerformSelector: @selector(printAllChildrenOfView)];

Всего одна строка кода.Конечно, вам может потребоваться настроить метод printAllChildrenOfView, чтобы он не принимал никаких параметров, или создать новый метод.

1 голос
/ 25 октября 2017

Это переписывание этого ответа:

Сначала вы должны получить указатель / ссылку на объект, который вы намереваетесь распечатать, все его подпредставления.Иногда вам может быть легче найти этот объект, обратившись к нему через его подпредставление.Как po someSubview.superview.Это даст вам что-то вроде:

Optional<UIView>
  ▿ some : <FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
  • FaceBookApp - это ваше имя приложения
  • WhatsNewView - это тип вашего superview
  • 0x7f91747c71f0 - указатель на суперпредставление.

Для печати superView необходимо использовать точки останова.


Теперь, чтобы сделать этот шаг, вы можете просто нажать на «Просмотреть иерархию отладки».Нет необходимости в точках останова

enter image description here

Тогда вы можете легко сделать:

po [0x7f91747c71f0 recursiveDescription]

, который для меня вернул что-то вроде:

<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>>

Как вы уже догадались, у моего суперпредставления есть 4 подпредставления:

  • a stackView (у самого stackView есть изображение и другой stackView (этот stackView имеет 2 пользовательских метки))
  • текстовое представление
  • представление
  • кнопка

Это довольно ново для меня, но помогло мнеотладить фреймы моих представлений (и текст, и тип).Одно из моих подпредставлений не отображалось на экране, поэтому я использовал recursiveDescription, и я понял, что ширина моего подпредставления была 0 ... поэтому я исправил его ограничения и появилось подпредставление.

1 голос
/ 09 октября 2015

Swift 2.0 совместимый

Здесь рекурсивный метод для получения всех подпредставлений общего вида:

extension UIView {
  func subviewsList() -> [UIView] {
      var subviews = self.subviews
      if subviews.count == 0 {
          return subviews + []
      }
      for v in subviews {
         subviews += v.listSubviewsOfView()
      }
      return subviews
  }
}

Таким образом, вы можете вызывать везде таким образом:

let view = FooController.view
let subviews = view.subviewsList()
1 голос
/ 08 июля 2016

enter image description here

Кратчайшее решение

for subview in self.view.subviews {
    print(subview.dynamicType)
}

Результат

UIView
UIView
UISlider
UISwitch
UITextField
_UILayoutGuide
_UILayoutGuide

Примечания

  • Как видите, этот метод не рекурсивно выводит список подпредставлений. Смотрите другие ответы на этот вопрос.
0 голосов
/ 30 августа 2011

self.view.subviews поддерживают иерархию представлений. Чтобы получить подпредставления uitableviewcell, вы должны сделать что-то вроде ниже.

 for (UIView *subView in self.view.subviews) {
      if ([subView isKindOfClass:[UITableView class]]) {
            for (UIView *tableSubview in subView.subviews) {
                .......
            }
      }
 }
0 голосов
/ 23 ноября 2016

Я сделал это в категории UIView, просто вызвав функцию, передающую индекс, чтобы напечатать их в хорошем формате дерева. Это просто еще один вариант ответа, который опубликовал Джеймс Вебстер .

#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++];
        }
    }
}

Надеюсь, это поможет :)

0 голосов
/ 10 октября 2016

A C # 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);
    }
}

В качестве альтернативы, если вы хотите найти все подпредставления определенного типа, который я использую:

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;

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...