Search This Blog

Friday, October 13, 2017

iOS Swift. How to get all subviews of UIView

The following task - get all subviews of provided view. There are several solutions how to do this.

1. Simple one - only first level of embedding


Just go through all subviews of view and add them to subview array. But in this solution only subviews on first level of embedding will be added to array.
func getSubviewsOfView(view: UIView) -> [UIView] {
    var subviewArray = [UIView]()
    for subview in view.subviews {
        subviewArray.append(subview)
    }
    return subviewArray
}

let subviews = self.getSubviewsOfView(view: self.view)

2. Getting all subviews - all embedded subviews (Recursively)


If we need to reach all subviews at all (all sub children) we must use recursive approach.
func getSubviewsOfView(view: UIView) -> [UIView] {
    var subviewArray = [UIView]()
    if view.subviews.count == 0 {
        return subviewArray
    }
    for subview in view.subviews {
        subviewArray += self.getSubviewsOfView(view: subview)
        subviewArray.append(subview)
    }
    return subviewArray
}

3. Getting all subviews of special type


If we need to collect only subviews of special class.  There we check every subview.
func getSubviewsOfView(view: UIView) -> [CustomView] {
        var subviewArray = [CustomView]()
        for subview in view.subviews {
            subviewArray += self.getSubviewsOfView(view: subview)
            if let subview = subview as? CustomView {
                subviewArray.append(subview)
            }
        }
        return subviewArray
    }

4. Getting all subviews using Generics - Getting subviews of any provided type


How can we improve method above. We can make it using Generics and after that it will collect subviews of provided type.
func getSubviewsOfView<T: UIView>(view: UIView) -> [T] {
    var subviewArray = [T]()
    if view.subviews.count == 0 {
        return subviewArray
    }
    for subview in view.subviews {
        subviewArray += self.getSubviewsOfView(view: subview) as [T]
        if let subview = subview as? T {
            subviewArray.append(subview)
        }
    }
    return subviewArray
}

Example of usage Generics function.
let allLabels: [UILabel] = self.getSubviewsOfView(view: self.view)
let allViews: [UIView] = self.getSubviewsOfView(view: self.view)

5. Generics and forEach loop


Also we can replace standard for loop with forEach loop
func getSubviewsOfView<T: UIView>(view: UIView) -> [T] {
    var subviewArray = [T]()
    guard view.subviews.count>0 else { return subviewArray }
    view.subviews.forEach{
        subviewArray += self.getSubviewsOfView(view: $0) as [T]
        if let subview = $0 as? T{
            subviewArray.append(subview)
        }
    }
    return subviewArray
}

6. Extension


But let's go further and make our solution more universal and available for all views in project.
Here we found Extension. Also here we add Bool parameter recursive for specifying do we need recursive search of subviews.
extension UIView {
    
    func getSubviewsOfView<T : UIView>(type : T.Type, recursive: Bool = false) -> [T] {
        return self.getSubviewsInner(view: self, recursive: recursive)
    }

    private func getSubviewsInner<T : UIView>(view: UIView, recursive: Bool = false) -> [T] {
        var subviewArray = [T]()
        guard view.subviews.count>0 else { return subviewArray }
        view.subviews.forEach {
            if recursive {
                subviewArray += self.getSubviewsInner(view: $0, recursive: recursive) as [T]
            }
            if let subview = $0 as? T{
                subviewArray.append(subview)
            }
        }
        return subviewArray
    }
    
}

Example of usage Extension.
let allLabels = self.view.getSubviewsOfView(type: UILabel.self, recursive: true)
let allViews = self.view.getSubviewsOfView(type: UIView.self, recursive: true)


7.Using Filter function


In swift we can use High-ordered function to filter collection. But this function will return only subviews of first embedded level. Here we getting all subviews of CustomView Type.
let allViews = self.view.subviews.filter { $0 is CustomView }


5 comments:

  1. After a long time i found a unique and on purpose information about Custom Designed Websites. Can't wait to have more from you.

    ReplyDelete
  2. You've provided some really useful information; I've been looking for material like this, so please keep sharing it as much as you can. Best Custom Websites

    ReplyDelete
  3. Thank you for writing this quality informational content.Your writing technique is impressive and enjoyable to read. I'll come back for more fantastic material.
    Best wishes, and good luck.
    Custom Build Website

    ReplyDelete
  4. your article is unbelievable with accurate information. I see a lot of research after that and that is more than I expectedCustom Build Website

    ReplyDelete