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

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

Ответы [ 22 ]

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

Вы должны рекурсивно перебирать подвиды.

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

Как прокомментировал @Greg Meletic, вы можете пропустить строку COUNT CHECK CHINEK выше.

35 голосов
/ 22 января 2012

Полезен встроенный способ xcode / gdb для вывода иерархии представлений - recursiveDescription, для http://developer.apple.com/library/ios/#technotes/tn2239/_index.html

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

> 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>>
13 голосов
/ 30 августа 2011

Вы должны печатать рекурсивно, этот метод также вкладки, основанные на глубине просмотра

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

}
12 голосов
/ 05 сентября 2016

Элегантное рекурсивное решение в Swift:

extension UIView {

    func subviewsRecursive() -> [UIView] {
        return subviews + subviews.flatMap { $0.subviewsRecursive() }
    }

}

Вы можете вызвать subviewsRecursive () для любого UIView:

let allSubviews = self.view.subviewsRecursive()
11 голосов
/ 16 июня 2014

Вот быстрая версия

 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)
    }
}
7 голосов
/ 29 июля 2012

Я немного опоздал на вечеринку, но немного более общее решение:

@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
6 голосов
/ 02 марта 2018

Если все, что вам нужно, это массив UIView s, это решение с одним вкладышем ( Swift 4 + ):

extension UIView {
  var allSubviews: [UIView] {
    return self.subviews.reduce([UIView]()) { $0 + [$1] + $1.allSubviews }
  }
}
5 голосов
/ 18 сентября 2012

Я использую этот способ:

NSLog(@"%@", [self.view subviews]);

в UIViewController.

4 голосов
/ 19 октября 2017

Подробности

  • Xcode 9.0.1, Swift 4
  • Xcode 10.2 (10E125), Swift 5

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

Использование

 view.printSubviews()
 print("\(view.allSubviews.count)")

Результат

enter image description here

3 голосов
/ 24 мая 2017

По-моему, категория или расширение UIView намного лучше, чем другие и рекурсивный является ключевым моментом для получения всех подпредставлений

узнать больше:

https://github.com/ZhipingYang/XYDebugView

enter image description here

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

пример

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

пример

let views = viewController.view.recurrenceAllSubviews()

напрямую, используйте функцию sequence , чтобы получить все подпредставления

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 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...