美文网首页iOS开发iOS开发iOS开发交流
检测任意view的subviews的关系树

检测任意view的subviews的关系树

作者: iOneWay | 来源:发表于2016-05-20 10:25 被阅读672次

    原文地址:http://www.glimsoft.com/01/07/how-to-inspect-subviews-hierarchy-of-any-uiview/

    一个简单的方式打印出任何UIView整个子视图层次(子类)。我们要通过创建UIView类,并添加一个递归方法来查看整个树结构。

    现在,可能有人想知道什么是‘category’:它是一种不需要继承任何类来向类中添加方法的一种简洁方式。想了解更多可以参考官方文档:documentation

    在某些情况下,当你在寻找一些基础的东西,比如MKMapView的组成;为了修改某些标签,等等,我觉得这种情况很多,所以没有必要再举例了。

    以下是我们的一个category(file UIView+printSubviews.h):

    #import <Foundation/Foundation.h>
    
    
    @interface UIView (PrintSubviews)
    
    - (void)printSubviewsWithIndentation:(int)indentation;
    
    @end
    

    Objective-C的Category声明十分简单且重要。更重要的是我们的方法可以在任何UIView及其子类(UIScrollView, MKMapView, UITableView, UIButton 等等)中工作。现在看看category的实现文件,如下代码:

    #import "UIView+printSubviews.h"
    
    
    @implementation UIView (PrintSubviews)
    
    - (void)printSubviewsWithIndentation:(int)indentation {
        
        NSArray *subviews = [self subviews];
        
        for (int i = 0; i < [subviews count]; i++) {
        
            UIView *currentSubview = [subviews objectAtIndex:i];
            NSMutableString *currentViewDescription = [[NSMutableString alloc] init];
            
            for (int j = 0; j <= indentation; j++) {
                [currentViewDescription appendString:@"   "];
            }
         
            [currentViewDescription appendFormat:@"[%d]: class: '%@', frame=(%.1f, %.1f, %.1f, %.1f), opaque=%i, hidden=%i, userInterfaction=%i", i, NSStringFromClass([currentSubview class]), currentSubview.frame.origin.x, currentSubview.frame.origin.y, currentSubview.frame.size.width, currentSubview.frame.size.height, currentSubview.opaque, currentSubview.hidden, currentSubview.userInteractionEnabled];
            
           
            fprintf(stderr,"%s\n", [currentViewDescription UTF8String]);
    
            [currentSubview printSubviewsWithIndentation:indentation+1];
        }
    }
    
    @end
    

    我觉得不需要作太多的解释,因为十分的简单。现在我将给大家展示一个使用实例,以及该方法所产生的输出。我要在一个有多个annotations,其中一个annotation被选中并弹出callout view的MKMapView上使用改方法。

    首先你需要在你将要使用的类中引入这个category的头文件:

    #import "UIView+printSubviews.h"
    

    然后在你希望检测的view上调用-printSubviewsWithIndentation:方法

    NSLog(@"*** Printing out all the subviews of MKMapView ***");
    [mapView printSubviewsWithIndentation:0];
    

    现在你可以看到如下的输出:


    现在你可以看到mapView中所有藏在屏幕后面的view了,每一行输出前面的[]中的数字代表该行的view在树结构中的层次索引。

    你可以向下面这样获取到MKAnnotationContainerView

    UIView *annotationContainerView = [[[[[[mapView subviews] objectAtIndex:0] subviews] objectAtIndex:0] subviews] objectAtIndex:1];
    

    当然,这种获取方式是不安全的,因为它取决于视图的特定顺序。所以你在使用以上方法获取对应视图的时候必须对它做一次测试:
    if [subviews count] > 0,或者使用像下面这样使用 NSClassFromString():

    for (UIView *subview in subviews) {
            if ([subview isKindOfClass:NSClassFromString(@"NameOfTheClass")]) {
                // We found the subview that we want
            }
        }
    

    最后我想提示大家,苹果不希望开发者这样做,因为一些UIKit类的子视图是私有的,因此他们将会在将来更改这些类。所以以上方法只能在你没有其他方式的情况下谨慎的使用。

    Swift版本

    extension UIView {
    
        func printSubviewsWithIndentation(indentation: Int) -> Void {
    
            for i in 0 ..< subviews.count {
                let currentView = subviews[i]
                
                var description = String()
                for _ in 0...indentation {
                    description += "  "
                }
                
                description += "[\(i)]: class:\(NSStringFromClass(currentView.dynamicType)): frame=\(currentView.frame), opaque=\((Int)(currentView.opaque)),hidden=\((Int)(currentView.hidden.boolValue)), userInteraction=\((Int)(currentView.userInteractionEnabled))"          
                print(description)
                currentView.printSubviewsWithIndentation(indentation + 1)
            }
        }
    
    }
    

    如有错误请指正,谢谢

    相关文章

      网友评论

      本文标题:检测任意view的subviews的关系树

      本文链接:https://www.haomeiwen.com/subject/hfqnrttx.html