Как я могу перебирать все подпункты UIView, а также их подзоны и их подпрограммы

Как я могу прокручивать все подпункты UIView, их подзонов и их подзонов?

Ответ 1

Использовать рекурсию:

// 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];

Ответ 2

Ну вот мое решение, использующее рекурсию и оболочку (категорию/расширение) для класса 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

Использование: теперь вам нужно перебирать все подпункты и манипулировать ими по мере необходимости.

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

Ответ 3

Просто нашел интересный способ сделать это через отладчик:

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

ссылается на Apple Technote:

http://developer.apple.com/library/ios/#technotes/tn2010/tn2239.html#SECUIKIT

Просто убедитесь, что ваш отладчик приостановлен (либо установите точку прерывания, чтобы приостановить его вручную), и вы можете запросить recursiveDescription.

Ответ 4

Я отмечаю все, когда он создается. Тогда легко найти любое под просмотр.

view = [aView viewWithTag:tag];

Ответ 5

Решение в Swift 3, которое дает все subviews без включения самого представления:

extension UIView {
var allSubViews : [UIView] {

        var array = [self.subviews].flatMap {$0}

        array.forEach { array.append(contentsOf: $0.allSubViews) }

        return array
    }
}

Ответ 6

С помощью Оле Бегеманна. Я добавил несколько строк, чтобы включить в него концепцию блока.

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

Использование категории иерархии в вашем ViewController. Теперь у вас есть свобода в том, что вам нужно делать.

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

Ответ 7

Вот рекурсивный код: -

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

Ответ 8

Кстати, я сделал проект с открытым исходным кодом, чтобы помочь в решении такого рода задач. Это очень просто и использует Objective-C 2.0 блоки для выполнения кода во всех представлениях в иерархии.

https://github.com/egold/UIViewRecursion

Пример:

-(void)makeAllSubviewsGreen
{
    [self.view runBlockOnAllSubviews:^(UIView *view) {

        view.backgroundColor = [UIColor greenColor];
    }];
}

Ответ 9

Не нужно создавать новую функцию. Просто делайте это при отладке с помощью Xcode.

Установите контрольную точку в контроллере представления и сделайте паузу приложения на этой точке останова.

Щелкните правой кнопкой мыши пустую область и нажмите "Добавить выражение..." в окне просмотра Xcode.

Введите эту строку:

(NSString*)[self->_view recursiveDescription]

Если значение слишком велико, щелкните его правой кнопкой мыши и выберите "Печать описания...". В окне консоли вы увидите все subviews self.view. Измените self → _ view на что-то еще, если вы не хотите видеть subviews self.view.

Готово! Нет gdb!

Ответ 10

Ниже приведен вариант ответа Ole Begemann, который добавляет отступы для иллюстрации иерархии:

// UIView+HierarchyLogging.h
@interface UIView (ViewHierarchyLogging)
- (void)logViewHierarchy:(NSString *)whiteSpaces;
@end

// UIView+HierarchyLogging.m
@implementation UIView (ViewHierarchyLogging)
- (void)logViewHierarchy:(NSString *)whiteSpaces {
    if (whiteSpaces == nil) {
        whiteSpaces = [NSString string];
    }
    NSLog(@"%@%@", whiteSpaces, self);

    NSString *adjustedWhiteSpaces = [whiteSpaces stringByAppendingFormat:@"    "];

    for (UIView *subview in self.subviews) {
        [subview logViewHierarchy:adjustedWhiteSpaces];
    }
}
@end

Ответ 11

Вот пример с фактической функцией циклизации и разлома представления.

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

Пример вызова:

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

Ответ 12

Код, отправленный в этом ответе, охватывает все окна и все представления и все их подпрограммы. Он использовался для сброса распечатки иерархии представлений в NSLog, но вы можете использовать ее в качестве основы для любого обхода иерархии представлений. Он использует рекурсивную функцию C, чтобы пересечь дерево представлений.

Ответ 13

Я написал категорию некоторое время назад для отладки некоторых видов.

IIRC, опубликованный код - тот, который работал. Если нет, он укажет вам в правильном направлении. Использовать на свой страх и риск и т.д.

Ответ 14

Здесь также отображается уровень иерархии

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

Ответ 15

Желаю, чтобы я сначала нашел эту страницу, но если (по какой-то причине) вы хотите сделать это нерекурсивно, а не в категории, и с более строки кода

Ответ 16

Я думаю, что все ответы, использующие рекурсию (за исключением опции отладчика), используют категории. Если вам не нужна/нужна категория, вы можете просто использовать метод экземпляра. Например, если вам нужно получить массив всех меток в иерархии представлений, вы можете сделать это.

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

Ответ 17

В приведенном ниже методе создается один или несколько изменяемых массивов, а затем проходит через подвыборы входного представления. При этом он добавляет начальное подчинение, а затем запросы относительно того, есть ли какие-либо подзадачи этого подвью. Если это правда, он снова называет себя. Он делает это до тех пор, пока не будут добавлены все представления иерархии.

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

Вызов с использованием:

NSArray * subviews = [self allSubs:someView];