我该如何循环遍历UIView的所有子视图、它们的子视图和它们的子视图?
我该如何循环遍历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类的包装器(category/extension)。
// 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;
}
}
allSubViews
函数存在内存泄漏问题:您必须将数组创建为 [[[NSMutableArray alloc] init] autorelease]
或 [NSMutableArray array]
(它们是相同的)。 - ivanzoid这里是另一个 Swift 实现:
extension UIView {
var allSubviews: [UIView] {
return self.subviews.flatMap { [$0] + $0.allSubviews }
}
}
Swift 3中提供的一个解决方案,可以获取所有subviews
但不包括视图本身:
extension UIView {
var allSubViews : [UIView] {
var array = [self.subviews].flatMap {$0}
array.forEach { array.append(contentsOf: $0.allSubViews) }
return array
}
}
nil
元素,以确保在对子视图调用 allSubViews
时安全。 - ielyamani我创建东西时都会打上标记,这样就很容易找到任何子视图了。
view = [aView viewWithTag:tag];
我刚刚通过调试器发现了一种有趣的方法:
http://idevrecipes.com/2011/02/10/exploring-iphone-view-hierarchies/
参考这篇苹果技术说明:
https://developer.apple.com/library/content/technotes/tn2239/_index.html#SECUIKIT
请确保您的调试器已经暂停(可以设置断点或手动暂停),然后可以请求 recursiveDescription
。
这里是一个具有实际视图循环和中断功能的示例。
Swift:
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;
}
}];
在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];
不需要创建任何新函数。在使用Xcode进行调试时,只需这样做。
在视图控制器中设置断点,并使应用程序在此断点处暂停。
在Xcode的监视窗口中右键单击空白区域,然后按“添加表达式…”。
输入以下行:
(NSString*)[self->_view recursiveDescription]
这是一个递归代码:
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];
}
}