Avoir le diable du temps à essayer de comprendre cela. J'ai posé une question similaire ici: Swift: Obtenir toutes les sous-vues d'un type spécifique et les ajouter à un tableau
Pendant que cela fonctionnait, j’ai réalisé qu’il existait de nombreuses sous-vues et sous-vues, et j’ai donc besoin d’une fonction qui commence par la fenêtre principale UIView, parcourt toutes les sous-vues (et leurs sous-vues jusqu’à ce qu’il ne reste plus aucune) et l’ajoute à un tableau pour une classe de boutons personnalisée que j'ai nommée CheckCircle.
Essentiellement, j'aimerais terminer avec un tableau de CheckCircles qui constituent tous les CheckCircles ajoutés à cette vue par programme.
Des idées? Voici ce sur quoi j'ai travaillé. Il ne semble pas ajouter de Checkcircles au tableau:
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
}
Votre principal problème est que lorsque vous appelez getSubviewsOfView(subview as! UIView)
(de manière récursive, dans la fonction), vous ne faites rien avec le résultat.
Vous pouvez également supprimer la vérification count == 0
car, dans ce cas, la boucle for…in
sera simplement ignorée. Vous avez également un tas de moulages inutiles
En supposant que votre désir soit d'obtenir un tableau plat d'instances CheckCircle
, je pense que cette adaptation de votre code devrait fonctionner:
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
}
Basé sur Aaron Brager et ullstrm answers
Swift 4, Xcode 9.1
extension UIView {
class func getAllSubviews<T: UIView>(view: UIView) -> [T] {
return view.subviews.flatMap { subView -> [T] in
var result = getAllSubviews(view: subView) as [T]
if let view = subView as? T {
result.append(view)
}
return result
}
}
func getAllSubviews<T: UIView>() -> [T] {
return UIView.getAllSubviews(view: self) as [T]
}
}
let allLabels = simpleView.getAllSubviews() as [UILabel]
Mon approche avec Swift 3 et les génériques!
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
}
Pour récupérer tous les UILabel dans une hiérarchie de vues, procédez comme suit:
let allLabels: [UILabel] = getSubviewsOf(view: theView)
Vous pouvez le mettre en œuvre simplement en étendant UIView et en définissant les fonctions suivantes.
Swift4 Code
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 }
}
}
Usage
findViews(subclassOf: UILabel.self)
findViews(subclassOf: CheckCircle.self)
uITextField n'est plus sur la couche supérieure des sous-vues, j'utilise donc cette méthode:
@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;
}
}
}
}
}
}
}
un peu long, mais devrait rendre compte du champ de texte se déplaçant plus profondément dans le futur
Basé sur Vasily Bodnarchuk , réponses de Aaron Brager , et ullstrm .
Personnellement, je n'aime pas avoir as [XXX]
et let specific: [Type]
, mais plutôt de passer le type à des appels de fonction, par exemple.
let scrollViews = view.getNestedSubviews(ofType: UIScrollView.self)
print(scrollViews) // outputs: [UIScrollView]
J'ai également renommé All
en Nested
car il transmet mieux la nature récursive de la fonction à l'appelant d'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]