web-dev-qa-db-fra.com

Swift: Obtenir toutes les sous-vues d'un type spécifique et les ajouter à un tableau

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?

29
Kenji Crosland

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.

58
vadian

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)
23
Mohammad Sadiq

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
11
Kametrixom

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)
11
ullstrm

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
}
5
Zaid Pathan
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)
3
Mustafa Alqudah

UIView a une propriété nommée subViews, vous pouvez voir l'API.

1
Siam

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

1
Vinh Nguyen

À 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 }
0
Diego Carrera