UISearchBar and UISearchBarDelegate

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.

  • Select the tableview and set View


  • 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 called `filtered` which holds the text which matches the text in the searchbar.

  • Depending on the `searchActive` we return either the `filtered` or the actual `data` in the `numberOfRowsInSection`
    and `cellForRowAtIndexPath`
Below is the complete code required to implement the functionality.

import UIKit
struct Candy {
    let category:String
    let name:String
}
class ViewController: UIViewController , UITableViewDelegate , UITableViewDataSource , UISearchBarDelegate , UISearchResultsUpdating{
    
    
    @IBOutlet weak var dataTableView: UITableView!
    var candies = [Candy]()
    var filteredCandies = [Candy]()
    
    let searchController = UISearchController(searchResultsController: nil)
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = true
        searchController.searchBar.placeholder = "Search Candies"
        definesPresentationContext = true
        
        self.navigationController?.navigationItem.searchController = searchController
        self.title = "Candies Name List"
        
        searchController.searchBar.scopeButtonTitles = ["All" , "Chocolate" , "Hard" , "Other"]
        searchController.searchBar.delegate = self
        
        dataTableView.tableHeaderView = searchController.searchBar
        
        candies = [Candy(category: "Chocolate", name: "Chocolate Bar"),
                   Candy(category: "Chocolate", name: "Chocolate Chip"),
                   Candy(category: "Chocolate", name: "Dark Chocolate"),
                   Candy(category: "Hard", name: "Lollipop"),
                   Candy(category: "Hard", name: "Jaw Breaker"),
                   Candy(category: "Hard", name: "Candy Cane"),
                   Candy(category: "Other", name: "Caramel"),
                   Candy(category: "Otehr", name: "Sour Chew"),
                   Candy(category: "Othert", name: "Gummi Bear"),
                   Candy(category: "Other", name: "Candy Floss"),
                   Candy(category: "Chocolate", name: "Chocolate Coin"),
                   Candy(category: "Chocolate", name: "Chocolate Egg"),
                   Candy(category: "Other", name: "Jelly Beans"),
                   Candy(category: "Other", name: "Liquorice"),
                   Candy(category: "Hard", name: "Toffee Apple")]
        
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if isFiltering() {
            return filteredCandies.count
        }
        return candies.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        let candy:Candy
        if isFiltering() {
          candy = filteredCandies[indexPath.row]
        } else {
            candy = candies[indexPath.row]
        }
        cell.textLabel?.text = candy.name
        cell.detailTextLabel?.text = candy.category
        return cell
    }
    func filterContentForSearchText(_ searchText:String , scope:String = "All")  {
       filteredCandies = candies.filter(
           
            { (candy:Candy) -> Bool in
                
                let doseCategoryMatch = (scope == "All") || (candy.category == scope)
                if searchBarIsEmpty() {
                    return doseCategoryMatch
                } else {
                    return doseCategoryMatch && candy.name.lowercased().contains(searchText.lowercased())
                }
            
        })
        dataTableView.reloadData()
    }
   
    func isFiltering() -> Bool {
        let searchBarScopeIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
        return searchController.isActive && (!searchBarIsEmpty() || searchBarScopeIsFiltering)
    }
    
    func searchBarIsEmpty() -> Bool {
        return searchController.searchBar.text?.isEmpty ?? true
    }
       func updateSearchResults(for searchController: UISearchController) {
        let searchBar = searchController.searchBar
        let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
        filterContentForSearchText(searchBar.text! , scope: scope)
    }
    
    func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        filterContentForSearchText(searchBar.text! , scope: searchBar.scopeButtonTitles![selectedScope])
    }
}
  • AppDelegate code required to implement the functionality.


//
//  AppDelegate.swift
//  UISearch
//
//  Copyright © 2018 WeeTech. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let storyBoard:UIStoryboard = UIStoryboard.init(name:"Main" , bundle:nil)
        let viewController :ViewController = storyBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
        let navigationController = UINavigationController.init(rootViewController: viewController)
        self.window?.rootViewController = navigationController
        self.window?.makeKeyAndVisible()
        return true
    }
    • Initial Load



    • On text in the textbar



    If you want to implement search using parse take.
    Please let me know if you have any feedback or questions.




    Comments

    Popular posts from this blog

    Easy way to learn Swift (IOS)