Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

More Table View Tricks for the iPhone : Page 2

Go beyond the basics of the iPhone Table View with examples for grouping rows into sections, displaying an index on the side, and adding a Search Bar.


advertisement

Adding Search Capabilities

Besides the ability to use an index to jump directly to a section, another very popular feature commonly found in the Table View is search. Using the Search Bar located at the top of the Table View, users can type a search keyword and the Table View dynamically shows the list of matching rows.

Let's see how you can add the search functionality to the Table View.

In the RootViewController.h file, add the following lines of code in bold:



#import "DetailsViewController.h" @interface RootViewController : UITableViewController { DetailsViewController *detailsViewController; IBOutlet UISearchBar *searchBar; BOOL isSearchOn; BOOL canSelectRow; NSMutableArray *searchResult; } @property (nonatomic, retain) DetailsViewController *detailsViewController; @property (nonatomic, retain) UISearchBar *searchBar; - (void) doneSearching: (id)sender; - (void) searchTableView; @end

You added an IBOutlet named searchBar so that you can connect to a Search Bar view in Interface Builder. You also added two Boolean variables and an NSMutableArray object to temporarily store the result of the search. In addition, you declared two methods, both which will be defined in the RootViewController.m file later.

Double-click on the RootViewController.xib file to edit it in Interface Builder. In the Table View window, add a Search Bar view (from the Library). Right-click on the Search Bar and connect the delegate to the File's Owner item (see Figure 3).

Control-click the File's Owner item and drag and drop it onto the Search Bar view. Select searchBar. If you right-click on the Search Bar view, you should see the connections as shown in Figure 4.


Figure 3. Connecting the Delegate Outlet to the File's Owner Item: Right-click on the Search Bar and connect the delegate to the File's Owner item.
 
Figure 4. The Connections Made for the Search Bar View: If you right-click on the Search Bar view, you should see these connections.

In the RootViewController.m file, first add in the following statement to create the getters and setters for the searchBar property:

#import "RootViewController.h" @implementation RootViewController @synthesize detailsViewController; @synthesize searchBar;

In the viewDidLoad method, add the following lines of code in bold:

- (void)viewDidLoad { //---initialize--- listOfStates = [[NSMutableArray alloc] init]; //---add items--- [listOfStates addObject:@"ALABAMA"]; [listOfStates addObject:@"ALASKA"]; //... //... [listOfStates addObject:@"WISCONSIN"]; [listOfStates addObject:@"WYOMING"]; //---create the index--- stateIndex = [[NSMutableArray alloc] init]; for (int i=0; i<[listOfStates count]-1; i++){ //---get the first char of each state--- char alphabet = [[listOfStates objectAtIndex:i] characterAtIndex:0]; NSString *uniChar = [NSString stringWithFormat:@"%C", alphabet]; //---add each alphabet to the index array--- if (![stateIndex containsObject:uniChar]) { [stateIndex addObject:uniChar]; } } //---set the correction type for the search bar--- searchBar.autocorrectionType = UITextAutocorrectionTypeYes; //---used for storing the search result--- searchResult = [[NSMutableArray alloc] init]; isSearchOn = NO; canSelectRow = YES; self.navigationItem.title = @"States of America"; [super viewDidLoad]; }

Implement the searchBarTextDidBeginEditing: method as shown below. This method will be called when the user taps on the Search Bar.

//---fired when the user taps on the Search Bar--- - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar { if ([searchResult count] > 0) { canSelectRow = YES; self.tableView.scrollEnabled = YES; } else { canSelectRow = NO; self.tableView.scrollEnabled = NO; } isSearchOn = YES; //---add the Done button at the top--- self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneSearching:)] autorelease]; }

When the user taps on the Search Bar, the keyboard will appear. In this searchBarTextDidBeginEditing: method, you first check to see if the temporary search result (searchResult) has any items in it. If it returns at least one item, the user will be able to scroll through the Table View. In addition, you add a Done button to the top right corner of the Navigation bar (see Figure 5). The Done button will invoke the doneSearching: method when the user taps it.

Figure 5. Displaying a Done Button to the Right of the Navigation Bar: You add a Done button to the top right corner of the Navigation bar.

Define the doneSearching: method as follows:

//---done with the searching--- - (void) doneSearching:(id)sender { searchBar.text = @""; isSearchOn = NO; canSelectRow = YES; self.tableView.scrollEnabled = YES; self.navigationItem.rightBarButtonItem = nil; //---hides the keyboard--- [searchBar resignFirstResponder]; //---refresh the Table View--- [self.tableView reloadData]; }

The doneSearching: method will clear the text in the Search Bar view and then hide the keyboard. It will also reload the Table View (via the reloadData method of the Table View) with the original set of 50 states. Next, implement the searchBar:textDidChange: method as shown below:

//---fired when the user types something into the Search Bar--- - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { [searchResult removeAllObjects]; //---if there is something to search for--- if ([searchText length] > 0) { isSearchOn = YES; canSelectRow = YES; self.tableView.scrollEnabled = YES; [self searchTableView]; } else { //---nothing to search--- isSearchOn = NO; canSelectRow = NO; self.tableView.scrollEnabled = NO; } [self.tableView reloadData]; }

The searchBar:textDidChange: method will be fired whenever the user types something into the Search Bar view. As the user types, the Search Bar view continually calls the searchTableView method, which you will define next. The searchTableView method iterates through the listOfStates object and looks for all states containing the search string. All matching states are stored in the searchResult object.

//---performs the searching using the array of states--- - (void) searchTableView { //---clears the search result--- [searchResult removeAllObjects]; for (NSString *str in listOfStates) { NSRange titleResultsRange = [str rangeOfString:searchBar.text options:NSCaseInsensitiveSearch]; if (titleResultsRange.length > 0) [searchResult addObject:str]; } }

Implement the searchBarSearchButtonClicked: method as shown below, which will be called when the user taps on the Search button on the keyboard:

//---fired when the user taps the Search button on the keyboard--- - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [self searchTableView]; }

Implement the tableView:willSelectRowAtIndexPath: method as shown below, which will be called just when the user selects a row:

//---fired before a row is selected--- - (NSIndexPath *)tableView :(UITableView *)theTableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (canSelectRow) return indexPath; else return nil; }

Modify the numberOfSectionsInTableView: method as shown below so that it will show a single section in the Table View when the user is performing the search:

//---set the number of sections in the table--- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { if (isSearchOn) return 1; else return [stateIndex count]; }

Modify the tableView:numberOfRowsInSection: method so that when the user is performing the search, the number of rows in the section is the number of items in the searchResult object:

//---set the number of rows in each section--- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (isSearchOn) { return [searchResult count]; } else { //---get the letter in each section; e.g., A, B, C, etc.--- NSString *alphabet = [stateIndex objectAtIndex:section]; //---get all states beginning with the letter--- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] %@", alphabet]; NSArray *states = [listOfStates filteredArrayUsingPredicate:predicate]; //---return the number of states beginning with the letter--- return [states count]; } }

Also, modify the tableView:titleForHeaderInSection: and sectionIndexTitlesForTableView: methods as follows. When performing the search, there is no need to display a title for the section nor to display the index.

//---set the title for each section--- - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (isSearchOn) return nil; else return [stateIndex objectAtIndex:section]; } //---set the index for the table--- - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { if (isSearchOn) return nil; else return stateIndex; }

In the tableView:cellForRowAtIndexPath: method, modify the code shown in bold below so that when performing a search, you will display the states saved in the searchResult object. When not searching, you will display the states in different sections, categorized by their beginning characters:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } if (isSearchOn) { NSString *cellValue = [searchResult objectAtIndex:indexPath.row]; cell.textLabel.text = cellValue; UIImage *image = [[UIImage imageNamed:@"USA.jpeg"] _imageScaledToSize:CGSizeMake(30.0f, 32.0f) interpolationQuality:1]; cell.imageView.image = image; cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; } else { //---get the letter in the current section--- id alphabet = [stateIndex objectAtIndex:[indexPath section]]; //---get all states beginning with the letter--- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] %@", alphabet]; NSArray *states = [listOfStates filteredArrayUsingPredicate:predicate]; if ([states count]>0) { NSString *cellValue = [states objectAtIndex:indexPath.row]; cell.textLabel.text = cellValue; UIImage *image = [[UIImage imageNamed:@"USA.jpeg"] _imageScaledToSize:CGSizeMake(30.0f, 32.0f) interpolationQuality:1]; cell.imageView.image = image; cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; } } return cell; }

You also need to modify the tableView:didSelectRowAtIndexPath: method so that you will display the appropriate states selected when the user performs a search:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *stateSelected; if (isSearchOn) { stateSelected = [searchResult objectAtIndex:indexPath.row]; } else { stateSelected = [listOfStates objectAtIndex:[indexPath row]]; } NSString *msg = [[NSString alloc] initWithFormat:@"You have selected %@", stateSelected]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"State selected" message:msg delegate:self cancelButtonTitle: @"OK" otherButtonTitles:nil]; [alert show]; [alert release]; [msg release]; }

Likewise, you need to modify the tableView:accessoryButtonTappedForRowWithIndexPath: method so that the appropriate state is selected when the user taps the disclosure button:

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { NSString *stateSelected; if (isSearchOn) { stateSelected = [searchResult objectAtIndex:indexPath.row]; } else { stateSelected = [listOfStates objectAtIndex:[indexPath row]]; } NSString *msg = [[NSString alloc] initWithFormat:@"You have selected %@", stateSelected]; //---Navigate to the details view--- if (self.detailsViewController == nil) { DetailsViewController *d = [[DetailsViewController alloc] initWithNibName:@"DetailsViewController" bundle:[NSBundle mainBundle]]; self.detailsViewController = d; [d release]; } //---set the state selected in the method of the // DetailsViewController---// [self.detailsViewController initWithTextSelected:msg]; [self.navigationController pushViewController:self.detailsViewController animated:YES]; [msg release]; }

Finally, release the searchBar property in the dealloc method:

- (void)dealloc { [self.detailsViewController release]; [listOfStates release]; [stateIndex release]; [searchBar release]; [super dealloc]; }

That's it! Press Command-R to test the application on the iPhone Simulator again. Tap on the Search Bar view to start the search. Observe that as you type in your search string, the Table View will display all the rows matching your search string (see Figure 6). When you are done with the search, tap on the Done button and the Table View will display the original list of 50 states.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap