4

I'm implementing an UISearchController to my UITableView but I'm struggling with the customization for iOS 11. My navigation bar is using a gradient image background that I want the search controller to match, but I haven't found a way to set the background image for UISearchController. It works perfectly on UISearchController as a TableHeaderView, but in iOS 11 barely any customization is passed on.

Current outcome:

Current outcome

Desired outcome:

Desired outcome

This is the code I'm using: (called on viewDidLoad)

private func setupSearchController() {

    let searchController = UISearchController(searchResultsController: nil)

    // Convert CAGradientLayer to UIImage
    let gradient = Color.blue.gradient
    gradient.frame = searchController.searchBar.bounds
    UIGraphicsBeginImageContext(gradient.bounds.size)
    gradient.render(in: UIGraphicsGetCurrentContext()!)
    let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    // Setup the Search Controller
    searchController.searchBar.backgroundImage = gradientImage
    searchController.searchBar.isTranslucent = false
    searchController.searchResultsUpdater = self
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.dimsBackgroundDuringPresentation = false
    searchController.obscuresBackgroundDuringPresentation = false
    searchController.searchBar.placeholder = "Search by transaction name"
    searchController.searchBar.tintColor = Color.custom(hexString: "FAFAFA", alpha: 1).value
    definesPresentationContext = true
    searchController.searchBar.delegate = self

    // Implement Search Controller
    if #available(iOS 11.0, *) {
        navigationItem.searchController = searchController
        navigationItem.hidesSearchBarWhenScrolling = false
        navigationController?.navigationBar.setBackgroundImage(gradientImage, for: .default)
    } else {
        tableView.tableHeaderView = searchController.searchBar
    }

}
nomadoda
  • 4,561
  • 3
  • 30
  • 45

3 Answers3

6

Thanks to Krunal's answer I was able to find a decent solution after searching for quite some time.

This is how I came about implementing the background-image for iOS 11:

    // Implement Search Controller
    if #available(iOS 11.0, *) {
        if let navigationBar = self.navigationController?.navigationBar {
            navigationBar.barTintColor = UIColor(patternImage: gradientImage!)
        }
        if let textField = searchController.searchBar.value(forKey: "searchField") as? UITextField {
            if let backgroundview = textField.subviews.first {
                backgroundview.backgroundColor = UIColor.white
                backgroundview.layer.cornerRadius = 10;
                backgroundview.clipsToBounds = true;

            }
        }
        navigationItem.searchController = searchController
        navigationItem.hidesSearchBarWhenScrolling = false
    } else {
        tableView.tableHeaderView = searchController.searchBar
    }
nomadoda
  • 4,561
  • 3
  • 30
  • 45
  • Is there a way to apply this method for vertical gradient. While applying it is coming as two sections for searchBar and navigation bar – Arunkrishna Aug 08 '18 at 11:32
0

You can add a CustomView for this. Use CustomView to add your searchBar to it, and then add this customView to your ViewController. Now you can easily set the background of this customView as:

//if customView is named as customView

    let backgroundImage = UIImageView(frame: UIScreen.mainScreen().bounds)
    backgroundImage.image = UIImage(named: "background.png")
    self.customView.insertSubview(backgroundImage, atIndex: 0)
Madhur
  • 1,056
  • 9
  • 14
  • Thanks! I would regard this as more of a hack than a solution, there should really be a way to customize standard implementation of a UISearchController – nomadoda Jan 22 '18 at 09:28
0

Swift 5, iOS 15

Considering searchController is a property of your class (vc most likely), navigation vc is not nil, "gradient" image is your asset with a gradient mix of some colors.
Put this code in your viewDidLoad to achieve a gradient navigation bar and a search field with a white background color.

let appearance = UINavigationBarAppearance()
appearance.backgroundImage = UIImage(named: "gradient")?.resizableImage(withCapInsets: .zero,
                                                                        resizingMode: .stretch)
navigationController?.navigationBar.scrollEdgeAppearance = appearance
navigationController?.navigationBar.standardAppearance = appearance

searchController = UISearchController(searchResultsController: nil)

/// Trick to have a white searchTextField background color, weird but it works.
searchController?.searchBar.searchTextField.borderStyle = .none
searchController?.searchBar.searchTextField.layer.cornerRadius = 10
searchController?.searchBar.searchTextField.layer.cornerCurve = .continuous
searchController?.searchBar.searchTextField.backgroundColor = .white

navigationItem.searchController = searchController

Result: enter image description here

Moving back from current vc you may want to reset your navigation bar to the default settings. For this purpose you may try to create UINavigationViewController extension with a handy function:

extension UINavigationController {

    func resetToDefaultAppearance() {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithDefaultBackground()

        navigationBar.standardAppearance = appearance
        navigationBar.scrollEdgeAppearance = appearance
        navigationBar.standardAppearance = appearance
        navigationBar.compactScrollEdgeAppearance = appearance
    }
}

Then call it in your viewWillDisappear:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    navigationController?.resetToDefaultAppearance()
}
Evgeny Karkan
  • 8,782
  • 2
  • 32
  • 38