有一段时间试图解决这个问题。我在这里问了一个类似的问题:Swift: Get all subviews of a specific type and add to an array
虽然这有效,但我意识到有很多子视图和子视图,因此我需要一个从主UIView开始的函数,循环遍历所有子视图(及其子视图,直到没有任何左视图并将其添加到一个自定义按钮类的数组中,我将其命名为CheckCircle。
基本上我想最终得到一个CheckCircles数组,它们构成了以编程方式添加到该视图的所有CheckCircles。
有什么想法吗?这是我一直在做的事情。它似乎没有将任何Checkcircles附加到数组中:
func getSubviewsOfView(v:UIView) -> [CheckCircle] {
var circleArray = [CheckCircle]()
// Get the subviews of the view
var subviews = v.subviews
if subviews.count == 0 {
return circleArray
}
for subview : AnyObject in subviews{
if let viewToAppend = subview as? CheckCircle {
circleArray.append(viewToAppend as CheckCircle)
}
getSubviewsOfView(subview as! UIView)
}
return circleArray
}
答案 0 :(得分:23)
你的主要问题是,当你在函数中递归getSubviewsOfView(subview as! UIView)
时,你不会对结果做任何事情。
您还可以删除count == 0
检查,因为在这种情况下,只会跳过for…in
循环。你还有一堆不必要的演员
假设您希望获得一系列CheckCircle
个实例,我认为您的代码适应性应该有效:
func getSubviewsOfView(v:UIView) -> [CheckCircle] {
var circleArray = [CheckCircle]()
for subview in v.subviews as! [UIView] {
circleArray += getSubviewsOfView(subview)
if subview is CheckCircle {
circleArray.append(subview as! CheckCircle)
}
}
return circleArray
}
答案 1 :(得分:18)
基于 Aaron Brager 和 ullstrm 答案
extension UIView {
class func getAllSubviews<T: UIView>(from parenView: UIView) -> [T] {
return parenView.subviews.flatMap { subView -> [T] in
var result = getAllSubviews(from: subView) as [T]
if let view = subView as? T { result.append(view) }
return result
}
}
func getAllSubviews<T: UIView>() -> [T] {
return UIView.getAllSubviews(from: self) as [T]
}
}
let allLabels = simpleView.getAllSubviews() as [UILabel]
另外,我建议使用弱引用。 Array with weak references to objects
答案 2 :(得分:14)
我使用swift 3和泛型的方法!
private func getSubviewsOf<T: UIView>(view: UIView) -> [T] {
var subviews = [T]()
for subview in view.subviews {
subviews += getSubviewsOf(view: subview) as [T]
if let subview = subview as? T {
subviews.append(subview)
}
}
return subviews
}
要获取视图层次结构中的所有UILabel,只需执行以下操作:
let allLabels: [UILabel] = getSubviewsOf(view: theView)
答案 3 :(得分:4)
您可以通过扩展UIView并定义以下功能来简单地实现它。
Swift4代码
extension UIView {
func findViews<T: UIView>(subclassOf: T.Type) -> [T] {
return recursiveSubviews.compactMap { $0 as? T }
}
var recursiveSubviews: [UIView] {
return subviews + subviews.flatMap { $0.recursiveSubviews }
}
}
用法
findViews(subclassOf: UILabel.self)
findViews(subclassOf: CheckCircle.self)
答案 4 :(得分:0)
基于 Vasily Bodnarchuk , Aaron Brager 和 ullstrm 的答案。
我个人不喜欢遍历as [XXX]
和let specific: [Type]
,而是将类型传递给函数调用,例如
let scrollViews = view.getNestedSubviews(ofType: UIScrollView.self)
print(scrollViews) // outputs: [UIScrollView]
我也将All
重命名为Nested
,因为它可以更好地将函数的递归性质传达给API调用者。
Swift 4.x,Xcode 9.1 +
extension UIView {
class func getNestedSubviews<T: UIView>(view: UIView) -> [T] {
return view.subviews.flatMap { subView -> [T] in
var result = getNestedSubviews(view: subView) as [T]
if let view = subView as? T {
result.append(view)
}
return result
}
}
func getNestedSubviews<T: UIView>() -> [T] {
return UIView.getNestedSubviews(view: self) as [T]
}
}
let scrollViews = view.getNestedSubviews(ofType: UIScrollView.self)
print(scrollViews) // outputs: [UIScrollView]
答案 5 :(得分:-1)
UITextField不再位于子视图的顶层,因此我使用此方法:
@implementation UISearchBar (changeFont)
- (void)setFont:(UIFont *)font {
for (UIView *v in [self subviews]) {
if ([v isKindOfClass:[UITextField class]]) {
UITextField *tf = (UITextField *)v;
tf.font = font;
UILabel *l = (UILabel *)[tf valueForKey:@"placeholderLabel"];
l.font = font;
break;
} else if (v.subviews.count) {
for (UIView *v1 in v.subviews) {
if ([v1 isKindOfClass:[UITextField class]]) {
UITextField *tf = (UITextField *)v1;
tf.font = font;
UILabel *l = (UILabel *)[tf valueForKey:@"placeholderLabel"];
l.font = font;
break;
} else if (v1.subviews.count) {
for (UIView *v2 in v1.subviews) {
if ([v2 isKindOfClass:[UITextField class]]) {
UITextField *tf = (UITextField *)v2;
tf.font = font;
UILabel *l = (UILabel *)[tf valueForKey:@"placeholderLabel"];
l.font = font;
break;
}
}
}
}
}
}
}
有点long绕,但应该说明将来文本字段会更深入