let subviews = view.subviews.noIMeanALLSubviews()

Table of Content

UISearchBar is neat

Earlier today I was making my first attempt at using the UISearchBar. It’s quite neat! The TL;DR of it is that it’s basically a UITextField with prebaked in functionality, specially designed to be used with a search function.

You see, I’ve been trying lately to make a conscious effort in making my apps, even my daily school-assignment-apps, into designs that are half way decent… Or at the very least, have a little thought put into them. But that led to a problem; I couldn’t control much about how it looked.
default search bar

I did eventually figure out (and it was surprisingly simple) how to change the grey into another color – it’s just the Bar Tint color in the attribute inspector in Interface Builder, but that left me with no choice other than the default blue of the embedded segment control when deciding which scope you want to search in. The stupid part is that setting it to the clear color just turns it black.

Determination

That was unacceptable. I couldn’t hand in an assignment with that blue clashing with the color scheme I had decided on. Well, I took matters into my own hands!

It occurred to me that the segmented control must just be a subview of search bar, so I set up a for loop to go through all of its subviews, attempting to cast each one as a UISegmentedControl and, if it worked, set the color. It didn’t work.

After some debugging, I found that I wasn’t wrong by thinking it’d be a subview, it was. However, it was a subview of a subview of a subview (or something like that) and the .subviews array only gives you the next generation of subviews, not ALL of them. So I had to get creative. I ended up writing an extension to UIView to recursively add all subviews of the view you call it on into a set, but then continue on recursively through all of its subviews’ subviews (and so on).

At this point, I bet you’re wonder what this code looks like. I’ll tell you want it looks like! It looks like this!!!

import UIKit

extension UIView {
    func allSubviews() -> Set<UIView> {
        var childSubviews = Set(subviews)
        for subview in subviews {
            childSubviews = childSubviews.union(subview.allSubviews())
        }
        return childSubviews
    }
}

I chose to put it in a set because I wanted to A. assure there were no duplicate entries (and there shoudn’t be regardless since each view can only be added to ONE super view), B. I didn’t care about the order, and C. sets are really fast at checking membership and joining up.

The Result

Putting this little gem to work allows me to write this:

for subview in searchBar.allSubviews() {
    if let selector = subview as? UISegmentedControl {
        selector.tintColor = .yellow
        selector.backgroundColor = .clear
    } 
}

Colored Search Bar

I wanna see the whole project!

If you want to check out a copy of the entire project, here’s a link to the branch in my BlogDemo repo.

Leave a Reply

Your email address will not be published. Required fields are marked *