kockburn
kockburn

Reputation: 17626

Change the style of the UISearchController views?

Question:

How do I change the color/theme/style of the UISearchController in tvOS?

( Would appear I need to set UIStatusBarStyle some way, since the preferredStatusBarStyle override does not exist in tvOS for UISearchController)

Description:

Method called in my AppDelegate to programmatically create a searchNavigationController with on top a UISearchController and on bottom my custom UITableViewController called "searchResultsController" (SearchViewController)

func configueSearchController() -> UIViewController {

    let storyboard = UIStoryboard(name: "Search", bundle: nil)
    guard let searchResultsController = storyboard.instantiateViewController(withIdentifier: SearchViewController.storyboardIdentifier) as? SearchViewController else {
        fatalError("Unable to instatiate a SearchResultViewController from the storyboard.")
    }

    /*
     Create a UISearchController, passing the `searchResultsController` to
     use to display search results.
     */

    let searchController = UISearchController(searchResultsController: searchResultsController)
    searchController.searchResultsUpdater = searchResultsController
    searchController.searchBar.placeholder = NSLocalizedString("Enter keyword (e.g. Gastric Bypass)", comment: "")

    // Contain the `UISearchController` in a `UISearchContainerViewController`.
    let searchContainer = UISearchContainerViewController(searchController: searchController)
    searchContainer.title = NSLocalizedString("Search", comment: "")

    // Finally contain the `UISearchContainerViewController` in a `UINavigationController`.
    let searchNavigationController = UINavigationController(rootViewController: searchContainer)
    return searchNavigationController

}

Image of the visual representation of the above method:

UISearchViewController

What I've tried:

I've attempted to change the style via different approaches and none of them gave the desired outcome.

This has no effect on the searchBar:

searchController.searchBar.searchBarStyle = .minimal //or .prominent or .default

This only makes the searchBar (actual input area black.. with black text..):

searchController.searchBar.backgroundColor = .black

This only makes the whole background view of the UISearchController black. Everything is black and thus the keyboard can not be seen.

searchController.view.backgroundColor = .black

The ideal solution would be a theme change from the standard .default to something .dark. Because not only does the background color have to change but the borders and text colors must too.

Attempted to implement this solution:

//UISearchController
override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

However, this override does not seem to exist for tvOS. Any reason why?

Upvotes: 5

Views: 3322

Answers (3)

tomo89aus
tomo89aus

Reputation: 31

For all those wanting to achieve this on tvOS with a TabBarController and storyboard, what I did was add a container view to my view controller and added the tab bar controller as a child.

class SearchController: UIViewController  {

    @IBOutlet var containerView: UIView!


    override func viewDidLoad() {
        super.viewDidLoad()

        let searchController = UISearchController.init(searchResultsController: nil)
        searchController.view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        searchController.view.frame = containerView.bounds        

        let searchContainer: UISearchContainerViewController = UISearchContainerViewController(searchController: searchController)

        // Finally contain the `UISearchContainerViewController` in a `UINavigationController`.
        let searchNavigationController = UINavigationController(rootViewController: searchContainer)
        searchNavigationController.navigationBar.isTranslucent = true
        searchNavigationController.navigationBar.tintColor = .black
        searchNavigationController.tabBarItem.title = "Search"

        containerView.addSubview(searchNavigationController.view)
        searchNavigationController.didMove(toParent: self)
    }
}

Upvotes: 3

quarterpi
quarterpi

Reputation: 863

I am not an expert on tvOS, but here's what I've found. I started with the UIKit Catalog: Creating and Customizing UIKit Controls example code from Apple. The first thing that I noticed is that the code you supplied above instantiates the searchResultsController as a SearchViewController, whereas Apple's example code instantiates the searchResultsController as a SearchResultsViewController. I assume you meant to do this.

After playing around with the example code, I was able to make very limited style changes. Here is a screenshot of the closest I have come to what it seems you are trying to achieve.

enter image description here

And here is the code that affected that change.

func packagedSearchController() -> UIViewController {
    // Load a `SearchResultsViewController` from its storyboard.
    let storyboard = UIStoryboard(name: "ViewControllerSamples", bundle: nil)
    guard let searchResultsController = storyboard.instantiateViewController(withIdentifier: SearchResultsViewController.storyboardIdentifier) as? SearchResultsViewController else {
        fatalError("Unable to instatiate a SearchResultsViewController from the storyboard.")
    }

    /*
        Create a UISearchController, passing the `searchResultsController` to
        use to display search results.
    */
    let searchController = UISearchController(searchResultsController: searchResultsController)
    searchController.searchResultsUpdater = searchResultsController
    searchController.searchBar.placeholder = NSLocalizedString("Enter keyword (e.g. iceland)", comment: "")

    //** This is the part you are interested in **//
    searchResultsController.view.backgroundColor = .black
    searchController.view.backgroundColor = UIColor(red: 0.25, green: 0.25, blue: 0.25, alpha: 1.0)
    searchController.searchBar.backgroundColor = .white

    // Contain the `UISearchController` in a `UISearchContainerViewController`.
    let searchContainer = UISearchContainerViewController(searchController: searchController)
    searchContainer.title = NSLocalizedString("Search", comment: "")

    // Finally contain the `UISearchContainerViewController` in a `UINavigationController`.
    let searchNavigationController = UINavigationController(rootViewController: searchContainer)
    return searchNavigationController
}

Unfortunately, I was unable to set the SearchController's view to .black without loosing the keyboard in the darkness. I looked and looked for a solution to the disappearing keyboard problem thinking that there must be a way to style the keyboard, or at least modify the selection state, all to no avail. My disappointment culminated in this statement from the App Programming Guide for tvOS: Designing the Keyboard Experience;

An inline keyboard displays all of the possible inputs on a single line. Use UISearchController to create a keyboard that can be fully integrated with third-party content. However, there are very few customization options when you use UISearchController. You can not access the text field itself, customize the traits, or add input accessories.

I suspect that if you could get a reference to that keyboard, you may be able to affect some change. That being said, I have not been able to find a real solution to date. Maybe you could attach a custom inputAccessoryViewController to the SearchController and effect a change that way?

Sorry I couldn't be more helpful.

Upvotes: 1

kockburn
kockburn

Reputation: 17626

There is a work around to this problem, however I don't really understand why they don't keep the same system as for iOS. Anyway, the main things to do to change the SearchBar style to black is to set the keyboardAppearance to dark, the searchController's view's background color and to set the searchBar's background color to white.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    guard let win = window else {
        return true
    }



    if let tabController = win.rootViewController as? UITabBarController {
        tabController.viewControllers?.append(configueSearchController())
    }

    win.backgroundColor = UIColor.white
    win.makeKeyAndVisible()

    return true
}   
func configueSearchController() -> UIViewController {

    let storyboard = UIStoryboard(name: "Search", bundle: nil)
    guard let searchResultsController = storyboard.instantiateViewController(withIdentifier: SearchViewController.storyboardIdentifier) as? SearchViewController else {
        fatalError("Unable to instatiate a SearchResultViewController from the storyboard.")
    }

    /*
     Create a UISearchController, passing the `searchResultsController` to
     use to display search results.
     */

    let searchController = UISearchController(searchResultsController: searchResultsController)
    searchController.searchResultsUpdater = searchResultsController
    searchController.searchBar.placeholder = NSLocalizedString("Enter keyword (e.g. Gastric Bypass)", comment: "")
    searchController.view.backgroundColor = UIColor.black
    searchController.searchBar.keyboardAppearance = UIKeyboardAppearance.dark
    searchController.searchBar.tintColor = UIColor.black
    searchController.searchBar.backgroundColor = UIColor.white
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.obscuresBackgroundDuringPresentation = true
    searchController.searchBar.searchBarStyle = .minimal
    searchController.searchBar.sizeToFit()

    //searchResultsController.tableView.tableHeaderView = searchController.searchBar

    // Contain the `UISearchController` in a `UISearchContainerViewController`.
    let searchContainer: UISearchContainerViewController = UISearchContainerViewController(searchController: searchController)

    // Finally contain the `UISearchContainerViewController` in a `UINavigationController`.
    let searchNavigationController = UINavigationController(rootViewController: searchContainer)
    searchNavigationController.navigationBar.isTranslucent = true
    searchNavigationController.navigationBar.tintColor = .black
    searchNavigationController.tabBarItem.title = "Search"
    return searchNavigationController

}

Upvotes: 1

Related Questions