Swift if Text Changes in Search Bar Search Again
Overview
Providing a way for users to search through a collection of items is a fairly mutual task in iOS projects. A standard interface for implementing search behaviors is the search bar.
There are a few common means to work with Search Confined:
-
Direct using a
UISearchBar. This is the near bare bones fashion to useUISearchBars. This tin be extremely flexible if you lot want to blueprint and program your own search interface, however does not provide equally many built-in features as the other methods. -
Using a
UISearchDisplayControllerto help manage a search interface. TheUISearchDisplayControllerallows you to present a standard search interface with born animations. This method forces you to display search results in a table view. - DEPRECATED -
Using a
UISearchControllerto assist manage a search interface. TheUISearchControlleris a newer controller (available just in iOS 8+) that helps you nowadays a search interface using any kind of view to display the search results.
This guide covers the very nuts of working with each of these classes. None of these classes really implements the "searching" behavior of finding items that lucifer a given query string, since determining which objects lucifer will vary with the domain specific apply case (e.g. when searching for "people" y'all might want to lucifer on just their names, whereas you may want a full-text pre-indexed search when searching through eastward-mails). You lot'll accept to implement any search/filtering behavior yourself.
Working with UISearchBars directly
At its core, a search bar is nothing more than than a glorified text field packaged with a scope command and some animations and a couple of buttons. Each search bar has a delegate that gives you an opportunity to respond to user actions. The almost important delegate methods are:
-
textDidChange- virtually of the fourth dimension you'll answer to this event by updating the displayed set up of search results as the user is typing out a query -
searchBarSearchButtonClicked- in some cases if the search operation is slow (e.one thousand. requires making a slow API call) y'all'll want to wait until the user taps the search button before updating the search results.
Example searching a tabular array
We showtime out with a single view awarding with a basic UITableView. You can add a UISearchBar as you would with any other control past dragging one to your view controller in interface builder or by programmatically calculation information technology.
The delegate property of search bar must be set to an object that implements UISearchBarDelegate. Typically you make your view controller implement UISearchBarDelegate and fix searchBar.consul = self in viewDidLoad method.
The code to implement the search behavior is as follows. Nosotros maintain an additional assortment filteredData to represent rows of data that match our search text. When the search text changes we update filteredData and reload our table. Find that we use filteredData as the backing array for the table view'south data source. The original data array is our source of truth since filteredData will exist changing constantly.
grade ViewController : UIViewController , UITableViewDataSource , UISearchBarDelegate { @IBOutlet weak var tableView : UITableView ! @IBOutlet weak var searchBar : UISearchBar ! let data = [ "New York, NY" , "Los Angeles, CA" , "Chicago, IL" , "Houston, TX" , "Philadelphia, PA" , "Phoenix, AZ" , "San Diego, CA" , "San Antonio, TX" , "Dallas, TX" , "Detroit, MI" , "San Jose, CA" , "Indianapolis, IN" , "Jacksonville, FL" , "San Francisco, CA" , "Columbus, OH" , "Austin, TX" , "Memphis, TN" , "Baltimore, Medico" , "Charlotte, ND" , "Fort Worth, TX" ] var filteredData : [ String ] ! override func viewDidLoad () { super . viewDidLoad () tableView . dataSource = self searchBar . delegate = cocky filteredData = data } func tableView ( _ tableView : UITableView , cellForRowAt indexPath : IndexPath ) -> UITableViewCell { let cell = tableView . dequeueReusableCell ( withIdentifier : "TableCell" , for : indexPath ) equally UITableViewCell cell . textLabel ? . text = filteredData [ indexPath . row ] return cell } func tableView ( _ tableView : UITableView , numberOfRowsInSection section : Int ) -> Int { return filteredData . count } // This method updates filteredData based on the text in the Search Box func searchBar ( _ searchBar : UISearchBar , textDidChange searchText : String ) { // When in that location is no text, filteredData is the same as the original data // When user has entered text into the search box // Utilize the filter method to iterate over all items in the data array // For each particular, return true if the item should be included and simulated if the // detail should Non exist included filteredData = searchText . isEmpty ? information : data . filter { ( item : Cord ) -> Bool in // If dataItem matches the searchText, return truthful to include it return item . range ( of : searchText , options : . caseInsensitive , range : nil , locale : nil ) != nada } tableView . reloadData () } } //SearchBarTableViewViewController.h @interface SearchBarTableViewViewController : UIViewController < UITableViewDelegate , UITableViewDataSource , UISearchBarDelegate > @end //SearchBarTableViewViewController.m @interface SearchBarTableViewViewController () @property ( potent , nonatomic ) IBOutlet UITableView * tableView ; @property ( strong , nonatomic ) NSArray * data ; @property ( strong , nonatomic ) NSArray * filteredData ; @property ( stiff , nonatomic ) IBOutlet UISearchBar * searchBar ; @end @implementation SearchBarTableViewViewController - ( void ) viewDidLoad { [ super viewDidLoad ]; self . tableView . delegate = self ; self . tableView . dataSource = cocky ; cocky . searchBar . delegate = self ; self . data = @[ @"New York, NY" , @"Los Angeles, CA" , @"Chicago, IL" , @"Houston, TX" , @"Philadelphia, PA" , @"Phoenix, AZ" , @"San Diego, CA" , @"San Antonio, TX" , @"Dallas, TX" , @"Detroit, MI" , @"San Jose, CA" , @"Indianapolis, IN" , @"Jacksonville, FL" , @"San Francisco, CA" , @"Columbus, OH" , @"Austin, TX" , @"Memphis, TN" , @"Baltimore, MD" , @"Charlotte, ND" , @"Fort Worth, TX" ]; cocky . filteredData = self . data ; } - ( NSInteger ) tableView : ( UITableView * ) tableView numberOfRowsInSection : ( NSInteger ) section { return self . filteredData . count ; } - ( UITableViewCell * ) tableView : ( UITableView * ) tableView cellForRowAtIndexPath : ( NSIndexPath * ) indexPath { UITableViewCell * jail cell = [ cocky . tableView dequeueReusableCellWithIdentifier : @"TableCell" forIndexPath : indexPath ]; cell . textLabel . text = self . filteredData [ indexPath . row ]; return cell ; } - ( void ) searchBar : ( UISearchBar * ) searchBar textDidChange : ( NSString * ) searchText { if ( searchText . length != 0 ) { NSPredicate * predicate = [ NSPredicate predicateWithBlock : ^ BOOL ( NSString * evaluatedObject , NSDictionary * bindings ) { return [ evaluatedObject containsString : searchText ]; }]; self . filteredData = [ self . data filteredArrayUsingPredicate : predicate ]; NSLog ( @"%@" , self . filteredData ); } else { self . filteredData = self . data ; } [ cocky . tableView reloadData ]; } @end Here'southward what this looks like when running. Notice that the search results are displayed in the aforementioned table, and in that location is no presentation of a separate search interface.
Example searching a collection view
Since the UISearchBar is quite elementary, it can exist combined with whatever arbitrary view to build your own search interface. Here's what it might look similar paired with a collection view.
The code for this is substantially the same equally in the case with table views.
Cancelling out of Search and hiding keyboard
In one case user taps on search bar, the keyboard volition announced, and y'all will observe that it won't get abroad when you tap on Ten. You lot can show Cancel button when user taps on search bar, and when user taps on Abolish, hide the keyboard.
In that location is a nifty searchBarTextDidBeginEditing method for UISearchBarDelegate that gets called when user starts editing search text. You can show Cancel button in that method:
func searchBarTextDidBeginEditing ( _ searchBar : UISearchBar ) { self . searchBar . showsCancelButton = true } - ( void ) searchBarTextDidBeginEditing :( UISearchBar * ) searchBar { self . searchBar . showsCancelButton = Yes ; } When user taps on abolish button, delegate's searchBarCancelButtonClicked method gets called. At this point, you can hide the Cancel button, clear existing text in search bar and hide the keyboard like this:
func searchBarCancelButtonClicked ( _ searchBar : UISearchBar ) { searchBar . showsCancelButton = false searchBar . text = "" searchBar . resignFirstResponder () } - ( void ) searchBarCancelButtonClicked :( UISearchBar * ) searchBar { cocky . searchBar . showsCancelButton = NO ; self . searchBar . text = @"" ; [ self . searchBar resignFirstResponder ]; } Using UISearchControllers (iOS eight+)
A newer way to manage the presentation of a search interface (only bachelor in iOS 8 and above) is via the UISearchController. This controller handles some of the logic and animation of presenting a separate search interface for yous while still assuasive yous to specify how your search results are displayed.
Example searching a table
There is currently no congenital-in object in the Interface Builder Object Library for a UISearchController. The easiest way to create one is to exercise it programmatically. This also creates a UISearchBar and sets the search controller'south searchBar holding to information technology. You lot tin add together this search bar to your view hierarchy programmatically.
In order to update your search results yous'll have to implement the UISearchResultsUpdating protocol and ready the search controller's searchResultsUpdater property.
Y'all don't need to implement the UISearchControllerDelegate unless you need to hook into the events effectually the presentation of the search interface.
Putting information technology all together the code looks like this. Observe that we have to read the search text from the search bar in updateSearchResults. Another thing to note is that nosotros set this view controller'due south definesPresentationContext holding to true. This ways the search controller should use this view controller'south frame (as opposed to the root view controller) when presenting the search interface. In this case, the search interface will expand to a higher place the carrier bar.
class ViewController : UIViewController , UITableViewDataSource , UISearchResultsUpdating { @IBOutlet weak var tableView : UITableView ! allow data = [ "New York, NY" , "Los Angeles, CA" , "Chicago, IL" , "Houston, TX" , "Philadelphia, PA" , "Phoenix, AZ" , "San Diego, CA" , "San Antonio, TX" , "Dallas, TX" , "Detroit, MI" , "San Jose, CA" , "Indianapolis, IN" , "Jacksonville, FL" , "San Francisco, CA" , "Columbus, OH" , "Austin, TX" , "Memphis, TN" , "Baltimore, MD" , "Charlotte, ND" , "Fort Worth, TX" ] var filteredData : [ String ] ! var searchController : UISearchController ! override func viewDidLoad () { super . viewDidLoad () tableView . dataSource = self filteredData = data // Initializing with searchResultsController set to aught means that // searchController will apply this view controller to display the search results searchController = UISearchController ( searchResultsController : nil ) searchController . searchResultsUpdater = self // If we are using this same view controller to nowadays the results // dimming information technology out wouldn't make sense. Should probably only set up // this to yep if using some other controller to brandish the search results. searchController . dimsBackgroundDuringPresentation = false searchController . searchBar . sizeToFit () tableView . tableHeaderView = searchController . searchBar // Sets this view controller as presenting view controller for the search interface definesPresentationContext = truthful } func tableView ( tableView : UITableView , cellForRowAtIndexPath indexPath : NSIndexPath ) -> UITableViewCell { let cell = tableView . dequeueReusableCell ( withIdentifier : "TableCell" ) ! cell . textLabel ? . text = filteredData [ indexPath . row ] return cell } func tableView ( tableView : UITableView , numberOfRowsInSection section : Int ) -> Int { return filteredData . count } func updateSearchResults ( for searchController : UISearchController ) { if allow searchText = searchController . searchBar . text { filteredData = searchText . isEmpty ? information : data . filter ({( dataString : String ) -> Bool in return dataString . rangeOfString ( searchText , options : . CaseInsensitiveSearch ) != zippo }) tableView . reloadData () } } } //UISearchViewController.h @interface UISearchViewController : UIViewController < UITableViewDelegate , UITableViewDataSource , UISearchResultsUpdating > @terminate //UISearchViewController.1000 @interface UISearchViewController () @holding ( strong , nonatomic ) IBOutlet UITableView * tableView ; @property ( strong , nonatomic ) UISearchController * searchController ; @property ( strong , nonatomic ) NSArray * information ; @property ( strong , nonatomic ) NSArray * filteredData ; @end @implementation UISearchViewController - ( void ) viewDidLoad { [ super viewDidLoad ]; self . tableView . consul = self ; self . tableView . dataSource = self ; cocky . information = @[ @"New York, NY" , @"Los Angeles, CA" , @"Chicago, IL" , @"Houston, TX" , @"Philadelphia, PA" , @"Phoenix, AZ" , @"San Diego, CA" , @"San Antonio, TX" , @"Dallas, TX" , @"Detroit, MI" , @"San Jose, CA" , @"Indianapolis, IN" , @"Jacksonville, FL" , @"San Francisco, CA" , @"Columbus, OH" , @"Austin, TX" , @"Memphis, TN" , @"Baltimore, MD" , @"Charlotte, ND" , @"Fort Worth, TX" ]; self . filteredData = self . data ; // Initializing with searchResultsController set up to nil ways that // searchController will apply this view controller to display the search results self . searchController = [[ UISearchController alloc ] initWithSearchResultsController : nil ]; cocky . searchController . searchResultsUpdater = self ; // If we are using this same view controller to present the results // dimming it out wouldn't make sense. Should probably only ready // this to yes if using another controller to display the search results. cocky . searchController . dimsBackgroundDuringPresentation = NO ; [ self . searchController . searchBar sizeToFit ]; self . tableView . tableHeaderView = self . searchController . searchBar ; // Sets this view controller every bit presenting view controller for the search interface cocky . definesPresentationContext = YES ; } - ( NSInteger ) tableView : ( UITableView * ) tableView numberOfRowsInSection : ( NSInteger ) section { render self . filteredData . count ; } - ( UITableViewCell * ) tableView : ( UITableView * ) tableView cellForRowAtIndexPath : ( NSIndexPath * ) indexPath { UITableViewCell * cell = [ self . tableView dequeueReusableCellWithIdentifier : @"TableCell" forIndexPath : indexPath ]; cell . textLabel . text = self . filteredData [ indexPath . row ]; render cell ; } - ( void ) updateSearchResultsForSearchController : ( UISearchController * ) searchController { NSString * searchText = searchController . searchBar . text ; if ( searchText ) { if ( searchText . length != 0 ) { NSPredicate * predicate = [ NSPredicate predicateWithBlock : ^ BOOL ( NSString * evaluatedObject , NSDictionary * bindings ) { return [ evaluatedObject containsString : searchText ]; }]; cocky . filteredData = [ self . data filteredArrayUsingPredicate : predicate ]; } else { self . filteredData = cocky . data ; } [ cocky . tableView reloadData ]; } } @terminate Hither's what this looks like when running. Notice that different in the search display controller instance, we are using the same table view to brandish the search results instead of overlaying of a separate table view. Yet, dissimilar when working with simply the search bar, we still have the built in animation when transitioning to the search interface.
As well, you lot become the logic to testify Abolish button and hide keyboard when user taps on cancel push for gratuitous when you employ this.
Example searching a collection view
We can just as easily use the search controller to search a collection view in identify. Nosotros nonetheless have the presentation of a search interface, but different when working with the search display controller we are not restricted to using a table view to brandish the search results.
The lawmaking for this is most the same equally when searching the the table view above. The but notable difference is that we had to introduce a placeholder view in interface builder for the search bar since at that place are yet some quirks with placing a search controller'south search bar inside a collection view'southward supplementary view.
class ViewController : UIViewController , UICollectionViewDataSource , UISearchResultsUpdating { @IBOutlet weak var collectionView : UICollectionView ! @IBOutlet weak var searchBarPlaceholder : UIView ! ... override func viewDidLoad () { ... searchController . searchBar . sizeToFit () searchBarPlaceholder . addSubview ( searchController . searchBar ) automaticallyAdjustsScrollViewInsets = false definesPresentationContext = true } ... } Search Bar in Navigation View
A common requirement is to place the search bar within the navigation bar.
This can be configured programmatically in your view controller's viewDidLoad as follows.
When working directly with a search bar:
// create the search bar programatically since you won't be // able to elevate one onto the navigation bar searchBar = UISearchBar () searchBar . sizeToFit () // the UIViewController comes with a navigationItem belongings // this volition automatically be initialized for you if when the // view controller is added to a navigation controller's stack // you lot just need to set the titleView to be the search bar navigationItem . titleView = searchBar // create the search bar programatically since you won't be // able to drag one onto the navigation bar self . searchBar = [[ UISearchBar alloc ] init ]; [ self . searchBar sizeToFit ]; // the UIViewController comes with a navigationItem property // this will automatically be initialized for you if when the // view controller is added to a navigation controller'due south stack // you merely need to gear up the titleView to be the search bar self . navigationItem . titleView = self . searchBar ; Using a search display controller:
searchDisplayController ? . displaysSearchBarInNavigationBar = true Using a search controller:
searchController . searchBar . sizeToFit () navigationItem . titleView = searchController . searchBar // By default the navigation bar hides when presenting the // search interface. Obviously we don't desire this to happen if // our search bar is inside the navigation bar. searchController . hidesNavigationBarDuringPresentation = simulated [ self . searchControllerNavi . searchBar sizeToFit ]; cocky . navigationItem . titleView = self . searchControllerNavi . searchBar ; // By default the navigation bar hides when presenting the // search interface. Obviously we don't want this to happen if // our search bar is inside the navigation bar. self . searchControllerNavi . hidesNavigationBarDuringPresentation = NO ; Source: https://guides.codepath.com/ios/Search-Bar-Guide
0 Response to "Swift if Text Changes in Search Bar Search Again"
Enviar um comentário