簡體   English   中英

如何遍歷UIView的所有子視圖及其子視圖和子視圖

[英]How can I loop through all subviews of a UIView, and their subviews and their subviews

如何遍歷UIView的所有子視圖及其子視圖和子視圖?

使用遞歸:

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

那么這里是我的解決方案,使用遞歸和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;
     }
}

Swift 3中的一個解決方案,它提供所有subviews而不包括視圖本身:

extension UIView {
var allSubViews : [UIView] {

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

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

        return array
    }
}

剛剛通過調試器找到了一種有趣的方法:

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

引用此Apple技術說明:

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

只需確保您的調試器已暫停(或者手動設置暫停的中斷點),您可以要求recursiveDescription

我在創建時標記所有內容。 然后很容易找到任何子視圖。

view = [aView viewWithTag:tag];

這是另一個Swift實現:

extension UIView {
    var allSubviews: [UIView] {
        return self.subviews.flatMap { [$0] + $0.allSubviews }
    }
}

在Ole Begemann的幫助下。 我添加了幾行來將塊概念合並到其中。

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中使用HierarchyLogging類別。 您現在可以自由地完成您需要做的事情。

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

以下是實際視圖循環和中斷功能的示例。

迅速:

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

無需創建任何新功能。 只需在使用Xcode進行調試時就可以了。

在視圖控制器中設置斷點,並使應用程序在此斷點處暫停。

右鍵單擊空白區域,然后在Xcode的Watch窗口中按“Add Expression ...”。

輸入這一行:

(NSString*)[self->_view recursiveDescription]

如果值太長,請右鍵單擊它並選擇“打印描述...”。 您將在控制台窗口中看到self.view的所有子視圖。 如果您不想查看self.view的子視圖,請將self - > _ view更改為其他內容。

完成! 沒有gdb!

這是一個遞歸代碼: -

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

順便說一下,我做了一個開源項目來幫助完成這類任務。 它非常簡單,並使用Objective-C 2.0塊來執行層次結構中所有視圖的代碼。

https://github.com/egold/UIViewRecursion

例:

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

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

以下是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

此答案中發布的代碼遍歷所有窗口以及所有視圖及其所有子視圖。 它用於將視圖層次結構的打印輸出轉儲到NSLog,但您可以將其用作任何遍歷視圖層次結構的基礎。 它使用遞歸C函數遍歷視圖樹。

希望我首先找到這個頁面 ,但是如果(出於某種原因)你想要非遞歸地執行此操作,而不是在類別中,並且需要更多行代碼

我在一段時間后寫了一個類別來調試一些視圖。

IIRC,發布的代碼是有效的。 如果沒有,它會指向正確的方向。 使用風險等

我認為使用遞歸的所有答案(調試器選項除外)都使用了類別。 如果您不需要/想要類別,則可以使用實例方法。 例如,如果需要在視圖層次結構中獲取所有標簽的數組,則可以執行此操作。

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

這也顯示了層次結構級別

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

下面的方法創建一個或多個可變數組,然后遍歷輸入視圖的子視圖。 在這樣做時,它會添加初始子視圖,然后查詢是否存在該子視圖的任何子視圖。 如果是真的,它會再次調用自己。 它會這樣做,直到添加了層次結構的所有視圖。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM