J'ai une classe de boutons personnalisée dans UIView que j'aimerais ajouter à un tableau pour qu'ils soient facilement accessibles. Est-il possible d'obtenir toutes les sous-vues d'une classe spécifique et de les ajouter à un tableau dans Swift?
La fonction filter
à l'aide de l'opérateur is
peut filtrer les éléments d'une classe spécifique.
let myViews = view.subviews.filter{$0 is MyButtonClass}
MyButtonClass
est la classe personnalisée à filtrer.
Voici
extension UIView {
/** This is the function to get subViews of a view of a particular type
*/
func subViews<T : UIView>(type : T.Type) -> [T]{
var all = [T]()
for view in self.subviews {
if let aView = view as? T{
all.append(aView)
}
}
return all
}
/** This is a function to get subViews of a particular type from view recursively. It would look recursively in all subviews and return back the subviews of the type T */
func allSubViewsOf<T : UIView>(type : T.Type) -> [T]{
var all = [T]()
func getSubview(view: UIView) {
if let aView = view as? T{
all.append(aView)
}
guard view.subviews.count>0 else { return }
view.subviews.forEach{ getSubview(view: $0) }
}
getSubview(view: self)
return all
}
}
Vous pouvez l'appeler comme
let allSubviews = view.allSubViewsOf(type: UIView.self)
let allLabels = view.allSubViewsOf(type: UILabel.self)
Je ne peux pas le tester maintenant mais cela devrait fonctionner dans Swift 2:
view.subviews.flatMap{ $0 as? YourView }
Ce qui retourne un tableau de YourView
Voici un exemple typique testé pour obtenir un décompte:
countDots = allDots!.view.subviews.flatMap{$0 as? Dot}.count
Pour ce faire de manière récursive (en récupérant également toutes les vues de sous-vues), vous pouvez utiliser cette fonction générique
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 toutes les étiquettes UIL dans une hiérarchie de vues, procédez comme suit:
let allLabels : [UILabel] = getSubviewsOf(view: theView)
Si vous souhaitez mettre à jour/accéder à ces sous-vues spécifiques, utilisez-le,
for (index,button) in (view.subviews.filter{$0 is UIButton}).enumerated(){
button.isHidden = false
}
func allSubViews(views: [UIView]) {
for view in views {
if let tf = view as? UITextField {
// Do Something
}
self.allSubViews(views: view.subviews)
}
}
self.allSubViews(views: self.view.subviews)
UIView a une propriété nommée subViews
, vous pouvez voir l'API.
Dans ce cas, je pense que nous pourrions utiliser la syntaxe first.where
de Swift, qui est plus efficace que filter.count
, filter.isEmpty
.
Parce que lorsque nous utilisons filter
, cela créera un tableau sous-jacent, donc non efficace, imaginons que nous ayons une grande collection.
Il suffit donc de vérifier si la collection subViews
d'une vue contient un type de classe spécifique, nous pouvons utiliser cette
let containsBannerViewKind = view.subviews.first(where: { $0 is BannerView }) != nil
qui équivaut à: trouvez-moi le premier match avec la classe BannerView dans la collection subViews de cette vue. Donc, si cela est vrai, nous pouvons poursuivre notre logique.
Référence: https://github.com/realm/SwiftLint/blob/master/Rules.md#first-where
À partir de Swift 4.1, vous pouvez utiliser le nouveau compactMap (flatMap est maintenant dépisté): https://developer.Apple.com/documentation/Swift/sequence/2950916-compactmap
Dans votre cas, vous pouvez utiliser:
let buttons:[UIButton] = stackView.subviews.compactMap{ $0 as? UIButton }
Et vous pouvez exécuter des actions sur tous les boutons en utilisant map:
let _ = stackView.subviews.compactMap{ $0 as? UIButton }.map { $0.isSelected = false }