Home » Swift » Swift: Get all subviews of a specific type and add to an array

Swift: Get all subviews of a specific type and add to an array

Posted by: admin November 30, 2017 Leave a comment

Questions:

I have a custom class of buttons in a UIView that I’d like to add to an array so that they’re easily accessible is there a way to. Get all subviews of with a specific class and add it to an array in Swift?

Answers:

The filter function using the is operator can filter items of a specific class.

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

MyButtonClass is the custom class to be filtered for.

Questions:
Answers:

Here you go

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

You can call it like

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

Questions:
Answers:

I can’t test it right now but this should work in Swift 2:

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

Which returns an array of YourView

Here’s a tested, typical example, to get a count:

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

Questions:
Answers:

To do this recursively (I.e. fetching all subview’s views aswell), you can use this generic function:

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
}

To fetch all UILabel’s in a view hierarchy, just do this:

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

Questions:
Answers:

If you want to update/access those specific subviews then use this,

for (index,button) in (view.subviews.filter{$0 is UIButton}).enumerated(){
    button.isHidden = false
}

Questions:
Answers:

UIView has a property named subViews, you can see the API.

Questions:
Answers:

For this case, I think we could use Swift’s first.where syntax, which is more efficient than filter.count, filter.isEmpty.

Because when we use filter, it will create a underlying array, thus not effective, imagine we have a large collection.

So just check if a view’s subViews collection contains a specific kind of class, we can use this

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

which equivalent to: find me the first match to BannerView class in this view’s subViews collection. So if this is true, we can carry out our further logic.

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