Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在iOS中列出uiviewcontroller中的所有子视图?_Ios_Uiview_Subview_Uiview Hierarchy - Fatal编程技术网

如何在iOS中列出uiviewcontroller中的所有子视图?

如何在iOS中列出uiviewcontroller中的所有子视图?,ios,uiview,subview,uiview-hierarchy,Ios,Uiview,Subview,Uiview Hierarchy,我想列出UIViewController中的所有子视图。我尝试了self.view.subview,但并没有列出所有的子视图,例如,UITableViewCell中的子视图没有找到。有什么想法吗?UITableViewCell中的子视图未打印的原因是您必须在顶层输出所有子视图。单元的子视图不是视图的直接子视图 为了获取UITableViewCell的子视图,您需要在打印循环中确定哪些子视图属于UITableViewCell(使用isKindOfClass:),然后在其子视图中循环 编辑:此博客文

我想列出
UIViewController
中的所有子视图。我尝试了
self.view.subview
,但并没有列出所有的子视图,例如,
UITableViewCell
中的子视图没有找到。有什么想法吗?

UITableViewCell中的子视图未打印的原因是您必须在顶层输出所有子视图。单元的子视图不是视图的直接子视图

为了获取UITableViewCell的子视图,您需要在打印循环中确定哪些子视图属于UITableViewCell(使用
isKindOfClass:
),然后在其子视图中循环


编辑:此博客文章可能有助于

self.view.subview维护视图的继承权。要获取uitableviewcell的子视图,您必须执行以下操作

 for (UIView *subView in self.view.subviews) {
      if ([subView isKindOfClass:[UITableView class]]) {
            for (UIView *tableSubview in subView.subviews) {
                .......
            }
      }
 }

您必须递归地迭代子视图

- (void)listSubviewsOfView:(UIView *)view {
    
    // Get the subviews of the view
    NSArray *subviews = [view subviews];

    for (UIView *subview in subviews) {
        
        // Do what you want to do with the subview
        NSLog(@"%@", subview);

        // List the subviews of subview
        [self listSubviewsOfView:subview];
    }
}

您需要递归打印,此方法还可以根据视图的深度设置选项卡

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

}
-(void)printAllChildrenOfView:(UIView*)节点深度:(int)d
{
//选项卡只是用于格式化
NSString*制表符=@;
对于(int i=0;i
您可以尝试一种奇特的数组技巧,如:

[self.view.subview makeObjectsPerformSelector:@selector(printAllChildrenOfView)]


只有一行代码。当然,您可能需要调整您的方法
printAllChildrenOfView
,以不接受任何参数或创建新方法。

内置的xcode/gdb转储视图层次结构的方法很有用——递归描述,根据

它会输出一个更完整的视图层次结构,您可能会发现它很有用:

> 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>>
>po[\u myToolbar recursiveDescription]
| 

我参加聚会有点晚了,但有一个更普遍的解决方案:

@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
我这样说:

NSLog(@"%@", [self.view subviews]);
let view = FooController.view
let subviews = view.subviewsList()

在UIViewController中。

我编写了一个类别,列出了一个视图控制器所持有的所有视图,其灵感来源于之前发布的答案

@interface UIView (ListSubviewHierarchy)
- (NSString *)listOfSubviews;
@end

@implementation UIView (ListSubviewHierarchy)
- (NSInteger)depth
{
    NSInteger depth = 0;
    if ([self superview]) {
        deepth = [[self superview] depth] + 1;
    }
    return depth;
}

- (NSString *)listOfSubviews
{
    NSString * indent = @"";
    NSInteger depth = [self depth];

    for (int counter = 0; counter < depth; counter ++) {
        indent = [indent stringByAppendingString:@"  "];
    }

    __block NSString * listOfSubviews = [NSString stringWithFormat:@"\n%@%@", indent, [self description];

    if ([self.subviews count] > 0) {
        [self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            UIView * subview = obj;
            listOfSubviews = [listOfSubviews stringByAppendingFormat:@"%@", [subview listOfSubviews]];
        }];
    }
    return listOfSubviews;
}
@end
界面UIView(ListSubviewHierarchy) -(NSString*)子视图列表; @结束 @实现UIView(ListSubviewHierarchy) -(NSInteger)深度 { NSInteger深度=0; 如果([自超视图]){ 深度=[[self superview]深度]+1; } 返回深度; } -(NSString*)子视图列表 { NSString*缩进=@; NSInteger深度=[自深度]; 用于(int计数器=0;计数器<深度;计数器++){ 缩进=[indent stringByAppendingString:@”“]; } __block NSString*listOfSubviews=[NSString stringWithFormat:@“\n%@%@”,缩进[自我描述]; 如果([self.subviews count]>0){ [self.subviews EnumerateObjectsSusingBlock:^(id obj,整数idx,布尔*停止){ UIView*子视图=obj; listOfSubviews=[listOfSubviews stringByAppendingFormat:@“%@,[subview listOfSubviews]]; }]; } 返回子视图列表; } @结束
要列出视图控制器持有的所有视图,只需
NSLog(%@,[self-listOfSubviews])
,它
self
表示视图控制器本身。尽管它不是很有效


另外,您可以使用
NSLog(@“\n%@,[(id)self.view performSelector:@selector(recursiveDescription)];
来做同样的事情,我认为它比我的实现更有效。

这是swift版本

 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)
    }
}
简单的Swift示例:

 var arrOfSub = self.view.subviews
 print("Number of Subviews: \(arrOfSub.count)")
 for item in arrOfSub {
    print(item)
 }

或者,如果要从UIView扩展返回所有子视图(和嵌套子视图)的数组,请执行以下操作:

func getAllSubviewsRecursively() -> [AnyObject] {
    var allSubviews: [AnyObject] = []

    for subview in self.subviews {
        if let subview = subview as? UIView {
            allSubviews.append(subview)
            allSubviews = allSubviews + subview.getAllSubviewsRecursively()
        }
    }

    return allSubviews
}

Swift 2.0兼容版

NSArray *views = [viewController.view recurrenceAllSubviews];
let views = viewController.view.recurrenceAllSubviews()
此处提供了一种递归方法,用于获取泛型视图的所有子视图:

extension UIView {
  func subviewsList() -> [UIView] {
      var subviews = self.subviews
      if subviews.count == 0 {
          return subviews + []
      }
      for v in subviews {
         subviews += v.listSubviewsOfView()
      }
      return subviews
  }
}
所以你可以用这种方式到处打电话:

NSLog(@"%@", [self.view subviews]);
let view = FooController.view
let subviews = view.subviewsList()

最短解

for subview in self.view.subviews {
    print(subview.dynamicType)
}
结果

UIView
UIView
UISlider
UISwitch
UITextField
_UILayoutGuide
_UILayoutGuide
注释

  • 如您所见,此方法不会递归列出子视图。请参阅其他一些答案

    • Swift中优雅的递归解决方案:

      extension UIView {
      
          func subviewsRecursive() -> [UIView] {
              return subviews + subviews.flatMap { $0.subviewsRecursive() }
          }
      
      }
      
      您可以在任何UIView上调用subviewsRecursive():

      let allSubviews = self.view.subviewsRecursive()
      
      C#Xamarin版本:

      void ListSubviewsOfView(UIView view)
      {
          var subviews = view.Subviews;
          if (subviews.Length == 0) return;
      
          foreach (var subView in subviews)
          {
              Console.WriteLine("Subview of type {0}", subView.GetType());
              ListSubviewsOfView(subView);
          }
      }
      
      或者,如果要查找我使用的特定类型的所有子视图,请执行以下操作:

      List<T> FindViews<T>(UIView view)
      {
          List<T> allSubviews = new List<T>();
          var subviews = view.Subviews.Where(x =>  x.GetType() == typeof(T)).ToList();
      
          if (subviews.Count == 0) return allSubviews;
      
             foreach (var subView in subviews)
             {
                  allSubviews.AddRange(FindViews<T>(subView));
              }
      
          return allSubviews;
      
      }
      
      列出FindView(UIView)
      {
      List allSubviews=新列表();
      var subviews=view.subviews.Where(x=>x.GetType()==typeof(T)).ToList();
      如果(subviews.Count==0)返回所有子视图;
      foreach(子视图中的var子视图)
      {
      AddRange(FindViews(subView));
      }
      返回所有子视图;
      }
      
      我已经在
      UIView的一个类别中完成了这项工作,只需调用传递索引的函数,以漂亮的树格式打印它们。这只是作者发布的答案的另一个选项

      #pragma标记-视图树
      -(无效)打印子视图街道索引:(NSInteger)索引
      {
      如果(!self)
      {
      返回;
      }
      NSString*tabSpace=@;
      @自动释放池
      {
      对于(NSInteger x=0;x

      我希望它能有所帮助:)

      在我看来,UIView的分类或扩展比其他分类或扩展要好得多 递归是获取所有子视图的关键

      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 }
      
      了解更多信息:

      目标-C Swift 3.1 示例

      NSArray *views = [viewController.view recurrenceAllSubviews];
      
      let views = viewController.view.recurrenceAllSubviews()
      
      直接使用序列函数获取所有子视图

      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 }
      
      细节
      • 代码9.0.1,Swift 4
      • 代码10.2(10E125),Swift 5
      解决方案 用法 结果 这是对答案的改写:

      您必须首先获取指向th的指针/引用
      Optional<UIView>
        ▿ some : <FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
      
      po [0x7f91747c71f0 recursiveDescription]
      
      <FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
         | <UIStackView: 0x7f91747c75f0; frame = (45 60; 264 93); layer = <CATransformLayer: 0x610000230ec0>>
         |    | <UIImageView: 0x7f916ef38c30; frame = (10.6667 0; 243 58); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x61000003b840>>
         |    | <UIStackView: 0x7f91747c8230; frame = (44.6667 58; 174.667 35); layer = <CATransformLayer: 0x6100006278c0>>
         |    |    | <FacebookApp.CopyableUILabel: 0x7f91747a80b0; baseClass = UILabel; frame = (44 0; 86.6667 16); text = 'What's New'; gestureRecognizers = <NSArray: 0x610000c4a770>; layer = <_UILabelLayer: 0x610000085550>>
         |    |    | <FacebookApp.CopyableUILabel: 0x7f916ef396a0; baseClass = UILabel; frame = (0 21; 174.667 14); text = 'Version 14.0.5c Oct 05, 2...'; gestureRecognizers = <NSArray: 0x610000c498a0>; layer = <_UILabelLayer: 0x610000087300>>
         | <UITextView: 0x7f917015ce00; frame = (45 183; 264 403); text = '   •   new Adding new feature...'; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x6100000538f0>; layer = <CALayer: 0x61000042f000>; contentOffset: {0, 0}; contentSize: {264, 890}>
         |    | <<_UITextContainerView: 0x7f9170a13350; frame = (0 0; 264 890); layer = <_UITextTiledLayer: 0x6080002c0930>> minSize = {0, 0}, maxSize = {1.7976931348623157e+308, 1.7976931348623157e+308}, textContainer = <NSTextContainer: 0x610000117b20 size = (264.000000,340282346638528859811704183484516925440.000000); widthTracksTextView = YES; heightTracksTextView = NO>; exclusionPaths = 0x61000001bc30; lineBreakMode = 0>
         |    |    | <_UITileLayer: 0x60800023f8a0> (layer)
         |    |    | <_UITileLayer: 0x60800023f3c0> (layer)
         |    |    | <_UITileLayer: 0x60800023f360> (layer)
         |    |    | <_UITileLayer: 0x60800023eca0> (layer)
         |    | <UIImageView: 0x7f9170a7d370; frame = (-39 397.667; 36 2.33333); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x60800023f4c0>>
         |    | <UIImageView: 0x7f9170a7d560; frame = (258.667 -39; 2.33333 36); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x60800023f5e0>>
         | <UIView: 0x7f916ef149c0; frame = (0 587; 354 0); layer = <CALayer: 0x6100006392a0>>
         | <UIButton: 0x7f91747a8730; frame = (0 0; 0 0); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x610000639320>>
         |    | <UIButtonLabel: 0x7f916ef00a80; frame = (0 -5.66667; 0 16); text = 'See More Details'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x610000084d80>>
      
      extension UIView {
        var allSubviews: [UIView] {
          return self.subviews.reduce([UIView]()) { $0 + [$1] + $1.allSubviews }
        }
      }
      
      - (NSString *)recusiveDescription:(UIView *)view
      {
          NSString *s = @"";
          NSArray *subviews = [view subviews];
          if ([subviews count] == 0) return @"no subviews";
      
          for (UIView *subView in subviews) {
               s = [NSString stringWithFormat:@"<%@; frame = (%f %f : %f %f) \n ",NSStringFromClass([subView class]), subView.frame.origin.x, subView.frame.origin.y ,subView.frame.size.width, subView.frame.size.height];  
              [self recusiveDescription:subView];
          }
          return s;
      }