Как я могу просмотреть все подпредставления UIView, их подпредставления и их подпредставления - PullRequest
76 голосов
/ 30 апреля 2010

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

Ответы [ 18 ]

120 голосов
/ 30 апреля 2010

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

// 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];
33 голосов
/ 15 декабря 2010

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

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

extension UIView {
var allSubViews : [UIView] {

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

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

        return array
    }
}
12 голосов
/ 19 февраля 2011

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

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

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

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

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

11 голосов
/ 07 июля 2011

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

view = [aView viewWithTag:tag];
7 голосов
/ 16 сентября 2011

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

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

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

void (^ViewActionBlock)(UIView *) = ^(UIView *view) {
    if ([view isKindOfClass:[UIButton class]]) {
        NSLog(@"%@", view);
    }
};
[self.view logViewHierarchy: ViewActionBlock];
6 голосов
/ 05 июня 2018

Вот еще одна реализация Swift:

extension UIView {
    var allSubviews: [UIView] {
        return self.subviews.flatMap { [$0] + $0.allSubviews }
    }
}
5 голосов
/ 16 сентября 2014

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

Swift:

extension UIView {

    func loopViewHierarchy(block: (_ view: UIView, _ stop: inout Bool) -> ()) {
        var stop = false
        block(self, &stop)
        if !stop {
            self.subviews.forEach { $0.loopViewHierarchy(block: block) }
        }
    }

}

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

mainView.loopViewHierarchy { (view, stop) in
    if view is UIButton {
        /// use the view
        stop = true
    }
}

Обратный цикл:

extension UIView {

    func loopViewHierarchyReversed(block: (_ view: UIView, _ stop: inout Bool) -> ()) {
        for i in stride(from: self.highestViewLevel(view: self), through: 1, by: -1) {
            let stop = self.loopView(view: self, level: i, block: block)
            if stop {
                break
            }
        }
    }

    private func loopView(view: UIView, level: Int, block: (_ view: UIView, _ stop: inout Bool) -> ()) -> Bool {
        if level == 1 {
            var stop = false
            block(view, &stop)
            return stop
        } else if level > 1 {
            for subview in view.subviews.reversed() {
            let stop = self.loopView(view: subview, level: level - 1, block: block)
                if stop {
                    return stop
                }
            }
        }
        return false
    }

    private func highestViewLevel(view: UIView) -> Int {
        var highestLevelForView = 0
        for subview in view.subviews.reversed() {
            let highestLevelForSubview = self.highestViewLevel(view: subview)
            highestLevelForView = max(highestLevelForView, highestLevelForSubview)
        }
        return highestLevelForView + 1
    }
}

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

mainView.loopViewHierarchyReversed { (view, stop) in
    if view is UIButton {
        /// use the view
        stop = true
    }
}

Objective-C:

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;
    }
}];
4 голосов
/ 24 октября 2012

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

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

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

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

(NSString*)[self->_view recursiveDescription]

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

Готово! Нет GDB!

4 голосов
/ 20 января 2012

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

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