Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom UISearchBar with UISearchController

The documentation for UISearchController says that you can override - searchBar to provide a custom subclass of UISearchBar for the controller to use. The custom search bar does get used, and its own delegate methods are called correctly, but the UISearchResultsUpdating method no longer gets called when the search bar changes. Do I need to do a lot of wiring things up manually, or is there something I'm missing to get the controller to behave like it does with a natively supplied search bar?

like image 225
farski Avatar asked Sep 18 '14 04:09

farski


3 Answers

Override the SearchBar getter in your custom UISearchController class, it have to return your custom SearchBar and it have to be already initialized, then you setup its properties only after the UISearchController init, this way all the UISearchController functionality are retained:

public class DSearchController: UISearchController {

    private var customSearchBar = DSearchBar()
    override public var searchBar: UISearchBar {
        get {
            return customSearchBar
        }
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    public init(searchResultsController: UIViewController?,
                searchResultsUpdater: UISearchResultsUpdating?,
                delegate: UISearchControllerDelegate?,
                dimsBackgroundDuringPresentation: Bool,
                hidesNavigationBarDuringPresentation: Bool,
                searchBarDelegate: UISearchBarDelegate?,
                searchBarFrame: CGRect?,
                searchBarStyle: UISearchBarStyle,
                searchBarPlaceHolder: String,
                searchBarFont: UIFont?,
                searchBarTextColor: UIColor?,
                searchBarBarTintColor: UIColor?, // Bar background
                searchBarTintColor: UIColor) { // Cursor and bottom line

        super.init(searchResultsController: searchResultsController)

        self.searchResultsUpdater = searchResultsUpdater
        self.delegate = delegate
        self.dimsBackgroundDuringPresentation = dimsBackgroundDuringPresentation
        self.hidesNavigationBarDuringPresentation = hidesNavigationBarDuringPresentation        

        customSearchBar.setUp(searchBarDelegate,
                              frame: searchBarFrame,
                              barStyle: searchBarStyle,
                              placeholder: searchBarPlaceHolder,
                              font: searchBarFont,
                              textColor: searchBarTextColor,
                              barTintColor: searchBarBarTintColor,
                              tintColor: searchBarTintColor)

    }
}

And this is my custom searchBar:

public class DSearchBar: UISearchBar {

    var preferredFont: UIFont?
    var preferredTextColor: UIColor?

    init(){
        super.init(frame: CGRect.zero)
    }

    func setUp(delegate: UISearchBarDelegate?,
               frame: CGRect?,
               barStyle: UISearchBarStyle,
               placeholder: String,
               font: UIFont?,
               textColor: UIColor?,
               barTintColor: UIColor?,
               tintColor: UIColor?) {

        self.delegate = delegate
        self.frame = frame ?? self.frame
        self.searchBarStyle = searchBarStyle
        self.placeholder = placeholder
        self.preferredFont = font
        self.preferredTextColor = textColor
        self.barTintColor = barTintColor ?? self.barTintColor
        self.tintColor = tintColor ?? self.tintColor
        self.bottomLineColor = tintColor ?? UIColor.clearColor()

        sizeToFit()

        //        translucent = false
        //        showsBookmarkButton = false
        //        showsCancelButton = true
        //        setShowsCancelButton(false, animated: false)
        //        customSearchBar.backgroundImage = UIImage()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }


    let bottomLine = CAShapeLayer()
    var bottomLineColor = UIColor.clearColor()

    override public func layoutSubviews() {
        super.layoutSubviews()

        for view in subviews {
            if let searchField = view as? UITextField { setSearchFieldAppearance(searchField); break }
            else {
                for sView in view.subviews {
                    if let searchField = sView as? UITextField { setSearchFieldAppearance(searchField); break }
                }
            }
        }

        bottomLine.path = UIBezierPath(rect: CGRectMake(0.0, frame.size.height - 1, frame.size.width, 1.0)).CGPath
        bottomLine.fillColor = bottomLineColor.CGColor
        layer.addSublayer(bottomLine)
    }

    func setSearchFieldAppearance(searchField: UITextField) {
        searchField.frame = CGRectMake(5.0, 5.0, frame.size.width - 10.0, frame.size.height - 10.0)
        searchField.font = preferredFont ?? searchField.font
        searchField.textColor = preferredTextColor ?? searchField.textColor
        //searchField.backgroundColor = UIColor.clearColor()
        //backgroundImage = UIImage()
    }

}

Init example:

searchController = DSearchController(searchResultsController: ls,
                                     searchResultsUpdater: self,
                                     delegate: self,
                                     dimsBackgroundDuringPresentation: true,
                                     hidesNavigationBarDuringPresentation: true,
                                     searchBarDelegate: ls,
                                     searchBarFrame: CGRectMake(0.0, 0.0, SCREEN_WIDTH, 44.0),
                                     searchBarStyle: .Minimal,
                                     searchBarPlaceHolder: NSLocalizedString("Search a location...", comment: ""),
                                     searchBarFont: nil,
                                     searchBarTextColor: nil,
                                     searchBarBarTintColor: UIColor.whiteColor(),
                                     searchBarTintColor: iconsColor)
searchController.searchBar.keyboardAppearance = .Dark
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
like image 157
Marco M Avatar answered Nov 15 '22 08:11

Marco M


This is a known bug. Unfortunately, there is no workaround that does not involve private API.

like image 28
MyztikJenz Avatar answered Nov 15 '22 09:11

MyztikJenz


When you subclass UISearchController you can customise UISearchBar in getter (setter doesn't exist).

Example - in subclass implementation:

-(UISearchBar*)searchBar{
     UISearchBar *baseSearchBar = [super searchBar];
    if (baseSearchBar.showsScopeBar) {
        baseSearchBar.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 88);
    }else{
        baseSearchBar.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44);
    }
    return baseSearchBar;
}

Hope this helps someone.

like image 2
DarkoM Avatar answered Nov 15 '22 09:11

DarkoM