wake-up-neo.com

Swift: Alle Unteransichten eines bestimmten Typs abrufen und einem Array hinzufügen

Ich habe eine benutzerdefinierte Klasse von Schaltflächen in einem UIView, die ich einem Array hinzufügen möchte, damit sie leicht zugänglich sind. Gibt es eine Möglichkeit, alle Unteransichten einer bestimmten Klasse abzurufen und sie einem Array in Swift hinzuzufügen?

29
Kenji Crosland

Die filter-Funktion, die den Operator is verwendet, kann Elemente einer bestimmten Klasse filtern. 

let myViews = view.subviews.filter{$0 is MyButtonClass}

MyButtonClass ist die benutzerdefinierte Klasse, nach der gefiltert werden soll.

58
vadian

Bitte schön 

    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
        }
    }

Du kannst es gerne nennen 

let allSubviews = view.allSubViewsOf(type: UIView.self)
let allLabels = view.allSubViewsOf(type: UILabel.self)
23
Mohammad Sadiq

Ich kann es jetzt nicht testen, aber das sollte in Swift 2 funktionieren:

view.subviews.flatMap{ $0 as? YourView }

Gibt ein Array von YourView zurück.

Hier ein typisches Beispiel, um eine Zählung zu erhalten:

countDots = allDots!.view.subviews.flatMap{$0 as? Dot}.count
11
Kametrixom

Um dies rekursiv durchzuführen (d. H. Auch alle Ansichten der Unteransichten abrufen), können Sie diese generische Funktion verwenden:

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
}

So rufen Sie alle UILabels in einer Ansichtshierarchie ab:

let allLabels : [UILabel] = getSubviewsOf(view: theView)
11
ullstrm

Wenn Sie diese bestimmten Unteransichten aktualisieren möchten, verwenden Sie diese,

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 hat eine Eigenschaft mit dem Namen subViews. Sie können die API sehen.

1
Siam

Ich denke, in diesem Fall könnten wir Swifts first.where-Syntax verwenden, die effizienter ist als filter.count, filter.isEmpty

Wenn wir filter verwenden, wird ein darunter liegendes Array erstellt, das also nicht effektiv ist. Stellen Sie sich vor, wir haben eine große Sammlung.

Prüfen Sie also einfach, ob die subViews-Sammlung einer Ansicht eine bestimmte Klasse enthält. Wir können dies verwenden

let containsBannerViewKind = view.subviews.first(where: { $0 is BannerView }) != nil

entspricht: Finden Sie die erste Übereinstimmung mit der BannerView-Klasse in der SubViews-Sammlung dieser Ansicht. Wenn dies wahr ist, können wir unsere weitere Logik ausführen.

Referenz: https://github.com/realm/SwiftLint/blob/master/Rules.md#first-where

1
Vinh Nguyen

Ab Swift 4.1 können Sie die neue compactMap verwenden (flatMap ist jetzt veraltet): https://developer.Apple.com/documentation/Swift/sequence/2950916-compactmap (Siehe Beispiele im Inneren) 

In Ihrem Fall können Sie verwenden:

let buttons:[UIButton] = stackView.subviews.compactMap{ $0 as? UIButton }

Und Sie können mit der Map Aktionen auf alle Buttons ausführen:

let _ = stackView.subviews.compactMap{ $0 as? UIButton }.map { $0.isSelected = false }
0
Diego Carrera

Lassen Sie mich meine Variation von diesem) posten, aber dies findet den ersten von T

extension UIView {

    func firstSubView<T: UIView>(ofType type: T.Type) -> T? {
        var resultView: T?
        for view in subviews {
            if let view = view as? T {
                resultView = view
                break
            }
            else {
                if let foundView = view.firstSubView(ofType: T.self) {
                    resultView = foundView
                    break
                }
            }
        }
        return resultView
    }
}
0
Mike Glukhov