Swift iOS Tutorial: UISearchBar and UISearchBarDelegate
One of the most important feature in an iOS application would be searching functionality, today we will be learning how to add search to our tableview application in Swift using UISearchBar and UISearchBarDelegate
UISearchBar
The UISearchBar class implements a text field control for text-based searches. The control provides a text field for entering text, a search button, a bookmark button, and a cancel button. The UISearchBar object does not actually perform any searches. You use a delegate, an object conforming to the UISearchBarDelegate protocol, to implement the actions when text is entered and buttons are clicked. You can hide and show the cancel button by setting showsCancelButton
to false or true.
UISearchBarDelegate
The UISearchBarDelegate protocol defines the optional methods you implement to make a UISearchBar control functional. A UISearchBar object provides the user interface for a search field on a bar, but it’s the application’s responsibility to implement the actions when buttons are tapped. At a minimum, the delegate needs to perform the actual search when text is entered in the text field.
The main function which we will be implementing are
optional func searchBar(_ searchBar: UISearchBar,
textDidChange searchText: String)
We will maintain a boolean variable searchActive
to decide if the search is in progress.
Steps to implement search
-
Create a single view application.
-
Disable Size classes for now.
-
Select the tableview and set the autolayout constraints to 0.
If you are interested in learning iOS Development I suggest you take a look at [Build an app every month]
-
To the existing controller add the tableview and a tableview cell on top of the tableview.Select the tableview Cell go to the attribute inspect and provide the identifier as
Cell
-
Select the view controller. Select Editor > Embed In > Navigation Controller.
-
Create IBOutlet from tableview and the searchbar.
CTRL+DRAG
from tableview and searchbar to the viewcontroller.swift -
Lets conform to the UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate. Also in viewDidLoad set the datasource and delegate to self.
/* Setup delegates */
tableView.delegate = self;
tableView.dataSource = self;
searchBar.delegate = self;
- Search functionality is very simple. We just filter the
data
array and if it matches the text we create a new array calledfiltered
which holds the text which matches the text in the searchbar. - Depending on the
searchActive
we return either thefiltered
or the actualdata
in thenumberOfRowsInSection
andcellForRowAtIndexPath
Below is the complete code required to implement the functionality.
//
// ViewController.swift
// SwiftSearch
//
// Created by Shrikar Archak on 2/16/15.
// Copyright (c) 2015 Shrikar Archak. All rights reserved.
//
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate{
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var tableView: UITableView!
var searchActive : Bool = false
var data = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
var filtered:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
/* Setup delegates */
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchActive = true;
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
filtered = data.filter({ (text) -> Bool in
let tmp: NSString = text
let range = tmp.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
return range.location != NSNotFound
})
if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive) {
return filtered.count
}
return data.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell;
if(searchActive){
cell.textLabel?.text = filtered[indexPath.row]
} else {
cell.textLabel?.text = data[indexPath.row];
}
return cell;
}
}
Initial Load
On text in the textbar
If you want to implement search using parse take a look at this tutorial Parse search in iOS8 with Swift Please let me know if you have any feedback or questions.
Requested tutorials from readers
To get this functionality we need to add these 3 function. First we need to change the style of the tableview from plain to grouped. Next we need to tell the height of the tableview header which in our case is 44. Also we need to creat a segmentedControl and return the control for TableView viewForHeaderInSection. In our case we want to change the data when segmented view Control value is changed. So we will addTarget to the segmentedControl which will be called when the value is changed.
/* Create these variable to hold different data *.
var data = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
var data0 = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
var data1 = ["Data1","Data11","Data111"]
var data2 = ["Data2","Data22","Data222"]
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let control = UISegmentedControl(items: ["Seg1","Seg2","Seg3"])
control.addTarget(self, action: "valueChanged:", forControlEvents: UIControlEvents.ValueChanged)
if(section == 0){
return control;
}
return nil;
}
func valueChanged(segmentedControl: UISegmentedControl) {
println("Coming in : (segmentedControl.selectedSegmentIndex)")
if(segmentedControl.selectedSegmentIndex == 0){
self.data = self.data0
} else if(segmentedControl.selectedSegmentIndex == 1){
self.data = self.data1
} else if(segmentedControl.selectedSegmentIndex == 2){
self.data = self.data2
} else {
self.data = data0
}
self.tableView.reloadData()
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44.0
}