How to Create iOS Custom Search Bar Using UISeachController

After iOS 8, things in iOS development have changed a bit.the UISearchDisplayController is now being deplored. And it is replaced by a new controller named as UISearchController. So now in order create custom iOS search bar in mobile app, you’ll need to use this new controller. There is no visual control exists anymore. It requires you to initialize and configure it programmatically. However, it’s not a difficult task, you’ll realize it later on. Just read on.

Besides this, there’s another interesting point regarding custom iOS search bar. The iOS SDK gives a predefined appearance for the iOS search bar and that bar works fluently in many cases. However, if the UI of mobile app is highly customized, then you might need to change the default look and feel of the search bar as it won’t fit in.

In this iOS app tutorial, we’ll demonstrate how you can create a new custom iOS search bar in your native application.

Let’s Get Started

Create a new project and select “Single View Application”.

searchcustom1

In the next tab, customize your project details and click on finish.

searchcustom2

After creating a new project, add a navigation controller and set “ViewController” as rootviewcontroller.

Next, add UITableView and UITextField in ViewController in Main.Storyboard and set IBOutlet in ViewController.swift class

@IBOutlet weak var txtSearchBar: UITextField!

@IBOutlet weak var tblCountry: UITableView!

searchcustom3

and set delegate of UITableView and UITextField.

Give Padding to UITextField by extension and set it into storyboard.

//Mark: UITextField extention for padding

class TextField: UITextField {

    

    let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 25);

    

    override func textRectForBounds(bounds: CGRect) -> CGRect {

        return UIEdgeInsetsInsetRect(bounds, padding)

    }

    

    override func placeholderRectForBounds(bounds: CGRect) -> CGRect {

        return UIEdgeInsetsInsetRect(bounds, padding)

    }

    

    override func editingRectForBounds(bounds: CGRect) -> CGRect {

        return UIEdgeInsetsInsetRect(bounds, padding)

    }

}

searchcustom4

Add two more button for Close and Cancel in ViewController and set IBOutlet.

@IBOutlet weak var btnClear: UIButton!

@IBOutlet weak var btnCancel: UIButton!

Get isSearch variable for differentiate search status.

var isSearch = false

Get all the country name in an array and load it in UITableView.

override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

        getAllCountryName()

    }

    

    func getAllCountryName() {

        let locale = NSLocale.currentLocale()

        let countryArray = NSLocale.ISOCountryCodes()

        var arrGetCountry = countryArray.map { (countryCode) -> String in

            return locale.displayNameForKey(NSLocaleCountryCode, value: countryCode)!

        }

        arrGetCountry = arrGetCountry.sort()

        arrCountry.addObjectsFromArray(arrGetCountry)

        tblCountry.reloadData()

    }

    //MARK: UITableViewDelegate

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 

{    

    }   

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        return 64

    }

    

    //MARK: UITableViewDataSource

    

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {

        return 1

    }

    

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        if isSearch == true {

            return arrSearch.count

        }

        return arrCountry.count

    }

    

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)

        configureCell(cell, forRowAtIndexPath: indexPath)

        return cell

    }

    

    func configureCell(cell: UITableViewCell, forRowAtIndexPath: NSIndexPath) {

        if isSearch == true {

            cell.textLabel?.text = arrSearch[forRowAtIndexPath.row] as? String

        } else {

            cell.textLabel?.text = arrCountry[forRowAtIndexPath.row] as? String

        }

    }

Manage the searching by UITextField delegates using following snippets.

//MARK: - UITextField Delegate -

    func textFieldDidChange(textField: UITextField) {

        self.arrSearch.removeAllObjects()

        if textField.text?.characters.count > 0 {

            isSearch = true

        }

        else {

            isSearch = false

        }

    }

    

    func textFieldDidBeginEditing(textField: UITextField) {

        UIView.animateWithDuration(0.3, delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {

            self.view.layoutIfNeeded()

        }) { (finished) in

            textField.becomeFirstResponder()

        }

        

        if isSearch {

            return

        }

        isSearch = true

        self.arrSearch.removeAllObjects()

    }

    

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

        

        let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)

        NSLog("%@", newString)

        

        if newString.characters.count == 0 {

            isSearch = false

            self.tblCountry.reloadData()

        } else {

            let sanitized: String = newString.stringByReplacingOccurrencesOfString("'", withString: "''")

            arrSearch.removeAllObjects()

            self.filteredArray(sanitized)

        }

        return true

    }

    

    func textFieldShouldReturn(textField: UITextField) -> Bool {

        if textField.text?.characters.count == 0 {

            isSearch = false

        } else {

            isSearch = true

        }

        self.tblCountry.reloadData()

        return textField.resignFirstResponder()

    }

    

    

    func filteredArray(searchString:NSString) {

        isSearch = true

        let predicate = NSPredicate(format: "SELF contains[c] %@",searchString)

        let filteredArray = arrCountry.filteredArrayUsingPredicate(predicate)

        print(filteredArray)

        arrSearch.addObjectsFromArray(filteredArray)

        tblCountry.reloadData()

    }

On click of Cancel button.

@IBAction func actionCancel(sender: AnyObject) {

        btnClear.enabled = false

        isSearch = false

        txtSearchBar.text = ""

        txtSearchBar.resignFirstResponder()

        tblCountry.reloadData()

    }

on click of Clear button.

@IBAction func actionClear(sender: AnyObject) {

        isSearch = false

        txtSearchBar.text = ""

        tblCountry.reloadData()

    }

And Done!

Now when you run the demo, it will look like this:

If you face any problem, you can contact our developers for help.

And now that you know how easy it is to work with UISearchController, you can add it in your iOS app pretty fast. If your application doesn’t demand UI changes according to your iOS app, then you can stick to the default appearance of the app. Although, you can make the look and feel of iOS search bar better if you hire swift developer to upgrade UI of custom iOS search bar.

Grab a free copy of UISearchController Example demo from Github.

This page was last edited on November 19th, 2016, at 16:01.
 
 

Want to Hire Expert Swift Developers? Contact Us Now

Get your free consultation now