如何列出iOS中uiviewcontroller中的所有子视图?
Posted
技术标签:
【中文标题】如何列出iOS中uiviewcontroller中的所有子视图?【英文标题】:How to list out all the subviews in a uiviewcontroller in iOS? 【发布时间】:2011-08-30 13:25:14 【问题描述】:我想列出UIViewController
中的所有子视图。我试过self.view.subviews
,但并不是所有的子视图都列出来了,比如UITableViewCell
中的子视图没有找到。有什么想法吗?
【问题讨论】:
您可以通过递归搜索找到所有子视图。即检查子视图有子视图.. 【参考方案1】:你必须递归地迭代子视图。
- (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];
【讨论】:
从技术上讲,您不需要检查子视图计数是否为 0。 NSLog(@"\n%@", [(id)self.view performSelector:@selector(recursiveDescription)]);此行打印的结果与您的相同! 如果您在这里,请查看来自@natbro 的更简单的recursiveDescription
答案 - ***.com/a/8962824/429521
这是我的 improvement 到 @EmptyStack 的解决方案。它以递归方式显示类名和框架坐标【参考方案2】:
转储视图层次结构的 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>>
【讨论】:
在我的代码或其他地方放置 po[_myToolbar recursiveDescription]
的位置。
@WildPointer 他说的是控制台。您需要在某处设置断点来执行此操作。 po = 打印对象
+1 Apple 推荐这种方法(根据 WWDC 2013 的 Cocoa 和 Cocoa Touch 会议中的隐藏宝石,提示 #5)。
@पवन 见我的回答here。我重写了这个答案。【参考方案3】:
Swift 中优雅的递归解决方案:
extension UIView
func subviewsRecursive() -> [UIView]
return subviews + subviews.flatMap $0.subviewsRecursive()
您可以在任何 UIView 上调用 subviewsRecursive():
let allSubviews = self.view.subviewsRecursive()
【讨论】:
【参考方案4】:你需要递归打印,这个方法也是基于视图深度的标签
-(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];
【讨论】:
【参考方案5】:这里是快速版本
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)
【讨论】:
【参考方案6】:我参加聚会有点晚了,但有一个更通用的解决方案:
@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
【讨论】:
【参考方案7】:详情
Xcode 9.0.1,Swift 4 Xcode 10.2 (10E125)、Swift 5解决方案
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)")
结果
【讨论】:
这有助于识别麻烦的子视图 - 谢谢【参考方案8】:如果您想要的只是UIView
s 的数组,这是一个单行解决方案(Swift 4+):
extension UIView
var allSubviews: [UIView]
return self.subviews.reduce([UIView]()) $0 + [$1] + $1.allSubviews
【讨论】:
感谢您的解决方案!我花了几个小时才弄清楚,但后来你的帖子救了我!【参考方案9】:我是这样用的:
NSLog(@"%@", [self.view subviews]);
在 UIViewController 中。
【讨论】:
【参考方案10】:以我的方式,UIView 的类别或扩展比其他的要好得多 而递归是获取所有子视图的关键
了解更多:
https://github.com/ZhipingYang/XYDebugView
目标-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];
斯威夫特 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
【讨论】:
【参考方案11】:简单的 Swift 示例:
var arrOfSub = self.view.subviews
print("Number of Subviews: \(arrOfSub.count)")
for item in arrOfSub
print(item)
【讨论】:
【参考方案12】:未打印 UITableViewCell 中的子视图的原因是您必须输出顶层的所有子视图。单元格的子视图不是您视图的直接子视图。
为了获取 UITableViewCell 的子视图,您需要在打印循环中确定哪些子视图属于 UITableViewCell(使用isKindOfClass:
),然后循环遍历它的子视图
编辑:Easy UIView Debugging 上的这篇博文可能会有所帮助
【讨论】:
【参考方案13】:我写了一个类别来列出视图控制器持有的所有视图,该视图控制器的灵感来自之前发布的答案。
@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
要列出视图控制器持有的所有视图,只需NSLog("%@",[self listOfSubviews])
,其中self
表示视图控制器本身。虽然效率不高。
另外,您可以使用NSLog(@"\n%@", [(id)self.view performSelector:@selector(recursiveDescription)]);
做同样的事情,我认为它比我的实现更有效。
【讨论】:
【参考方案14】:你可以尝试一个花哨的数组技巧,比如:
[self.view.subviews makeObjectsPerformSelector: @selector(printAllChildrenOfView)];
只有一行代码。当然,您可能需要调整您的方法printAllChildrenOfView
,使其不带任何参数或创建新方法。
【讨论】:
【参考方案15】:兼容 Swift 2.0
这里有一个递归方法来获取一个通用视图的所有子视图:
extension UIView
func subviewsList() -> [UIView]
var subviews = self.subviews
if subviews.count == 0
return subviews + []
for v in subviews
subviews += v.listSubviewsOfView()
return subviews
所以你可以用这种方式到处调用:
let view = FooController.view
let subviews = view.subviewsList()
【讨论】:
【参考方案16】:最短的解决方案
for subview in self.view.subviews
print(subview.dynamicType)
结果
UIView
UIView
UISlider
UISwitch
UITextField
_UILayoutGuide
_UILayoutGuide
备注
如您所见,此方法不会递归地列出子视图。请参阅其他一些答案。【讨论】:
【参考方案17】:这是this答案的重写:
您必须首先获取要打印其所有子视图的对象的指针/引用。有时您可能会发现通过其子视图访问该对象更容易找到该对象。喜欢po someSubview.superview
。这会给你类似的东西:
Optional<UIView>
▿ some : <FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
FaceBookApp 是你的应用名称
WhatsNewView 是您的superview
的类型
0x7f91747c71f0
是指向父视图的指针。
要打印superView,必须使用断点。
现在要执行此步骤,您只需单击“查看调试层次结构”。无需断点
那么你可以轻松做到:
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>>
你一定猜到了我的超级视图有 4 个子视图:
一个stackView(stackView本身有一个图像和另一个stackView(这个stackView有2个自定义标签)) 一个文本视图 一个视图 一个按钮这对我来说相当新,但帮助我调试了我的视图框架(以及文本和类型)。我的一个子视图没有显示在屏幕上,所以使用了 recursiveDescription,我意识到我的一个子视图的宽度是 0
... 所以我纠正了它的约束并且子视图出现了。
【讨论】:
【参考方案18】:或者,如果您想从 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
【讨论】:
【参考方案19】: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;
【讨论】:
【参考方案20】:我已经在UIView
的类别中完成了它,只需调用传递索引的函数以使用漂亮的树格式打印它们。这只是James Webster 发布的答案的另一种选择。
#pragma mark - Views Tree
- (void)printSubviewsTreeWithIndex:(NSInteger)index
if (!self)
return;
NSString *tabSpace = @"";
@autoreleasepool
for (NSInteger x = 0; x < index; x++)
tabSpace = [tabSpace stringByAppendingString:@"\t"];
NSLog(@"%@%@", tabSpace, self);
if (!self.subviews)
return;
@autoreleasepool
for (UIView *subView in self.subviews)
[subView printViewsTreeWithIndex:index++];
希望对你有帮助:)
【讨论】:
【参考方案21】:- (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;
【讨论】:
【参考方案22】:self.view.subviews 维护视图的层次结构。要获取 uitableviewcell 的子视图,您必须执行以下操作。
for (UIView *subView in self.view.subviews)
if ([subView isKindOfClass:[UITableView class]])
for (UIView *tableSubview in subView.subviews)
.......
【讨论】:
以上是关于如何列出iOS中uiviewcontroller中的所有子视图?的主要内容,如果未能解决你的问题,请参考以下文章
Swift - iOS 9:如何在 iOS 9 中呈现具有自定义大小的 UIViewController? [复制]
如何在 ios5 的 UIViewController 中显示 UIView?
iOS:如何在弹出其子 UIViewController 后“刷新” UIViewController?
如何在 iOS 中滑动 UIViewController 中包含的子视图控制器?