I have a regular TableViewController and want to add a UITextField above that will populate the TableView data. How I can programmatically place right above the cells?
Thanks
You could place the UITextField in the UITableViewController's header.
Use the UITableViewController Delegate methods to set the properties of the header.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
Alternatively, you could use a UISearchBar.
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 0)];
searchBar.delegate = self;
[searchBar sizeToFit];
tableView.tableHeaderView = searchBar;
Then, in the UISearchBar delegate methods.
#pragma mark - UISearchBar Delegate Methods
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
// Remove the keyboard
[searchBar endEditing:YES];
// This method filters the data based on the search text.
[self filterDataUsingSearchText:searchBar.text];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
// Remove the keyboard
[searchBar endEditing:YES];
// Clear the text on cancel
searchBar.text = #"";
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
// This method filters the data based on the search text.
[self filterDataUsingSearchText:searchText];
}
#pragma mark -
Documentation:
UISearchBar Reference
Table View Programming Guide
Related
I am getting the above warning message when trying to run my code.
NSDictionary *tempDictionary = nil;
if (self.tableView == self.searchDisplayController.searchResultsTableView) {
tempDictionary = [filteredCompanyArray objectAtIndex:indexPath.row];
}
else {
tempDictionary= [self.client_list objectAtIndex:indexPath.row];
}
It's been deprecated and did a google search but all I saw were tutorials in Swift.
I followed Ray Wenderlich tutorial here http://www.raywenderlich.com/16873/how-to-add-search-into-a-table-view but now i'm stuck.
#pragma mark Content Filtering
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.filteredCompanyArray removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.name contains[c] %#",searchText];
filteredCompanyArray = [NSMutableArray arrayWithArray:[self.client_list filteredArrayUsingPredicate:predicate]];
}
#pragma mark - UISearchDisplayController Delegate Methods
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// Tells the table data source to reload when text changes
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
// Tells the table data source to reload when scope bar selection changes
[self filterContentForSearchText:self.searchDisplayController.searchBar.text scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
The recipe below worked for me. I just successfully updated multiple scenarios of former iOS 7 code.
Thanks also to the inspiration of Updating to the iOS 8 Search Controller and Apple's API Reference
Remove UISearchDisplayDelegate protocol, add UISearchResultsUpdating and maybe UISearchControllerDelegate instead
#interface YOURTableviewController : UIViewController <UITableViewDelegate, UITableViewDataSource, /*UISearchDisplayDelegate, <- Removed*/ UISearchResultsUpdating /* Added */, UISearchControllerDelegate /* Added */>
{
Add new UISearchController as property:
// New property
#property (nonatomic, strong) UISearchController *searchController;
// ...
#implementation YOURTableviewController
#synthesize searchController; // New property
and initialize the new property in the didLoad method
- (void)viewDidLoad
{
// New code start -
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.delegate = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.searchController.searchBar.barTintColor = [UIColor orangeColor];
[self.tableview setTableHeaderView:self.searchController.searchBar];
self.definesPresentationContext = YES;
// - New code end
// Previous code
//self.searchDisplayController.searchBar.barTintColor = [UIColor orange];
[super viewDidLoad];
}
Add new UISearchResultsUpdating methods, update UISearchBarDelegate methods, and maybe add helping extra method like below, and maybe also UISearchControllerDelegate methods
#pragma mark -
#pragma mark UISearchResultsUpdating
- (void)updateSearchResultsForSearchController:(UISearchController *)_searchController
{
NSString *searchString = _searchController.searchBar.text;
[self searchForText:searchString];
[self.tableview reloadData];
}
#pragma mark -
#pragma mark UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[self updateSearchResultsForSearchController:self.searchController];
}
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
{
[self updateSearchResultsForSearchController:self.searchController];
}
// Extra method
- (void)searchForText:(NSString *)searchString
{
/* Put here everything that is in the method:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
...BUT WITH NO RETURN VALUE */
}
#pragma mark -
#pragma mark UISearchControllerDelegate
- (void)willPresentSearchController:(UISearchController *)searchController
{
//..
}
- (void)didPresentSearchController:(UISearchController *)searchController
{
//..
}
- (void)willDismissSearchController:(UISearchController *)searchController
{
//..
}
- (void)didDismissSearchController:(UISearchController *)searchController
{
//..
}
Replace and remove obsolete UISearchDisplayDelegate method(s)
#pragma mark -
#pragma mark UISearchDisplayDelegate
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{ ... }
Replace 'searchDisplayController' everywhere with 'searchController'
Make replacements
Code like:
if (tableView == self.searchDisplayController.searchResultsTableView)
can be replaced with
if (self.searchController.isActive)
Code like:
[self.searchDisplayController setActive:YES];
can be replaced with
[self.searchController setActive:YES];
Yes UISearchDisplay Controller is deprecated, you should use UISearchController instead
Create Search Controller First
#property (strong, nonatomic) UISearchController *searchController;
Initialise Search controller properties
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
Bind Search controller with your table view
self.tableView.tableHeaderView = self.searchController.searchBar;
Implement UISearchResultUpdating delegate
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
NSString *searchString = searchController.searchBar.text;
[self searchForText:searchString
scope:searchController.searchBar.selectedScopeButtonIndex];
[self.tableView reloadData];
}
You Can also use your filter method to filter result
Your search logic will go here
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
More detail you can find
http://useyourloaf.com/blog/updating-to-the-ios-8-search-controller/
As UISearchDisplayController is deprecated, you need to use UISearchController for your purpose. Follow this link Using UISearchController
Another link that might be useful for you UISearchController Vs UISearchDisplayController
I am using UISearchbar in tableview controller in storyboard.
And searchbar returnKeyType is UIReturnKeySearch.
Its working fine with iOS7 but returnKeyType is not working with iOS8.
in iOS8, return key appears every time in keyboard.
I tried to set returnkeytype in viewDidLoad method of controller too.
What I need to do to set returnKeyType = UIReturnKeySearch in iOS8?
I think you can go with your hard codded logic for right now.
I will update if I will get better solution for your problem.
-(void)viewDidLoad {
[self setReturnKeyTypeSearchForView:searchBar];
}
-(void)setReturnKeyTypeSearchForView:(UIView *)view
{
for (id subView in view.subviews) {
if ([subView isKindOfClass:[UITextField class]]) {
[subView setReturnKeyType:UIReturnKeySearch];
}
else {
[self setReturnKeyTypeSearchForView:subView];
}
}
if ([view isKindOfClass:[UITextField class]]) {
[(UITextField *)view setReturnKeyType:UIReturnKeySearch];
}
}
Try making IBOutlet of your SearchBar
#property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
and add the below line code to your viewDidLoad Method
// if u want Done return key and change accordingly.
_searchBar.returnKeyType = UIReturnKeyDone;
SearchViewController.h
//
#import <UIKit/UIKit.h>
#interface SearchViewController : UIViewController
<UISearchBarDelegate, UITableViewDataSource> {
NSMutableArray *tableData;
UIView *disableViewOverlay;
UITableView *theTableView;
UISearchBar *theSearchBar;
}
#property(retain) NSMutableArray *tableData;
#property(retain) UIView *disableViewOverlay;
#property (nonatomic, retain) IBOutlet UITableView *theTableView;
#property (nonatomic, retain) IBOutlet UISearchBar *theSearchBar;
- (void)searchBar:(UISearchBar *)searchBar activate:(BOOL) active;
#end
SearchViewController.m
//
#import "SearchViewController.h"
#implementation SearchViewController
#synthesize tableData;
#synthesize disableViewOverlay;
#synthesize theSearchBar;
#synthesize theTableView;
// Initialize tableData and disabledViewOverlay
- (void)viewDidLoad {
[super viewDidLoad];
self.tableData =[[NSMutableArray alloc]init];
self.disableViewOverlay = [[UIView alloc]
initWithFrame:CGRectMake(0.0f,44.0f,320.0f,416.0f)];
self.disableViewOverlay.backgroundColor=[UIColor blackColor];
self.disableViewOverlay.alpha = 0;
}
// Since this view is only for searching give the UISearchBar
// focus right away
- (void)viewDidAppear:(BOOL)animated {
[self.theSearchBar becomeFirstResponder];
[super viewDidAppear:animated];
}
#pragma mark -
#pragma mark UISearchBarDelegate Methods
- (void)searchBar:(UISearchBar *)searchBar
textDidChange:(NSString *)searchText {
// We don't want to do anything until the user clicks
// the 'Search' button.
// If you wanted to display results as the user types
// you would do that here.
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
// searchBarTextDidBeginEditing is called whenever
// focus is given to the UISearchBar
// call our activate method so that we can do some
// additional things when the UISearchBar shows.
[self searchBar:searchBar activate:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
// searchBarTextDidEndEditing is fired whenever the
// UISearchBar loses focus
// We don't need to do anything here.
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
// Clear the search text
// Deactivate the UISearchBar
searchBar.text=#"";
[self searchBar:searchBar activate:NO];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
// Do the search and show the results in tableview
// Deactivate the UISearchBar
// You'll probably want to do this on another thread
// SomeService is just a dummy class representing some
// api that you are using to do the search
NSArray *results = [SomeService doSearch:searchBar.text];
[self searchBar:searchBar activate:NO];
[self.tableData removeAllObjects];
[self.tableData addObjectsFromArray:results];
[self.theTableView reloadData];
}
// We call this when we want to activate/deactivate the UISearchBar
// Depending on active (YES/NO) we disable/enable selection and
// scrolling on the UITableView
// Show/Hide the UISearchBar Cancel button
// Fade the screen In/Out with the disableViewOverlay and
// simple Animations
- (void)searchBar:(UISearchBar *)searchBar activate:(BOOL) active{
self.theTableView.allowsSelection = !active;
self.theTableView.scrollEnabled = !active;
if (!active) {
[disableViewOverlay removeFromSuperview];
[searchBar resignFirstResponder];
} else {
self.disableViewOverlay.alpha = 0;
[self.view addSubview:self.disableViewOverlay];
[UIView beginAnimations:#"FadeIn" context:nil];
[UIView setAnimationDuration:0.5];
self.disableViewOverlay.alpha = 0.6;
[UIView commitAnimations];
// probably not needed if you have a details view since you
// will go there on selection
NSIndexPath *selected = [self.theTableView
indexPathForSelectedRow];
if (selected) {
[self.theTableView deselectRowAtIndexPath:selected
animated:NO];
}
}
[searchBar setShowsCancelButton:active animated:YES];
}
#pragma mark -
#pragma mark UITableViewDataSource Methods
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"SearchResult";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
id *data = [self.tableData objectAtIndex:indexPath.row];
cell.textLabel.text = data.name;
return cell;
}
#pragma mark -
#pragma mark Memory Management Methods
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[theTableView release], theTableView = nil;
[theSearchBar release], theSearchBar = nil;
[tableData dealloc];
[disableViewOverlay dealloc];
[super dealloc];
}
#end
Building a SearchView with UISearchBar and UITableView
this might helps you :)
I'm not sure if I understood your question correctly. You want to have "search" button instead of "return" button, right? There is a new SearchController in ios 8, give it a try:
YourTableViewController.h
#interface YourTableViewController : UITableViewController<UISearchResultsUpdating>
#end
And now the implementation:
YourTableViewController.m
- (void)viewDidLoad {
// initializing with the same controller as presenting
UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
searchController.searchResultsUpdater = self;
searchController.searchBar.frame = CGRectMake(searchController.searchBar.frame.origin.x, searchController.searchBar.frame.origin.y, searchController.searchBar.frame.size.width, 44.0f);
searchController.dimsBackgroundDuringPresentation = NO;
searchController.searchBar.delegate = self;
searchController.searchBar.returnKeyType = UIReturnKeySearch; //should be search by default.. you can change to whatever you want.
// adding searchBar into HeaderView
self.tableView.tableHeaderView = searchController.searchBar;
// just to be able to present results on the same controller
self.definesPresentationContext = YES;
}
You also have to implement method from UISearchResultsUpdating protocol:
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
// you can leave it blank
}
EDIT: If it is not what you were looking for please comment, so I can update my answer accordingly
try this in viewDidLoad:
UITextField *txfSearchField = [yourSearchbar valueForKey:#"_searchField"];
if([txfSearchField conformsToProtocol:#protocol(UITextInputTraits)]) {
[txfSearchField setReturnKeyType:UIReturnKeyDefault];
}
I've created a UISearchBar in one of my ViewControllers that contain different containers that link to other ViewControllers. This UISearchBar is in the parent ViewController. I am trying to grab the text that was entered in the search bar to be used to send to another ViewController The UISearchBar was created in StoryBoard. I am using the following methods to try and receive information from the Search Bar:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
NSLog(#"searching");
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(#"Text change");
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Cancel clicked");
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Search Clicked");
}
Non of these functions above seem to run, I am not sure why. Suggestions or thoughts?
UPDATE:
Here is what I am using to initiate the Search Bar now:
_aSearchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
[_aSearchBar sizeToFit];
_aSearchBar.delegate = self;
_aSearchBar.placeholder = #"Search YouTube...";
_searchDC = [[UISearchDisplayController alloc] initWithSearchBar:_aSearchBar contentsController:self];
[self performSelector:#selector(setSearchDisplayController:) withObject:_searchDC];
_searchDC.delegate = self;
_searchDC.searchResultsDataSource = self;
_searchDC.searchResultsDelegate = self;
[_aSearchBar release];
NSLog(#"%#",[_searchDC.delegate class]); <------ this prints home which is the correct class
Now the only issue is, I can't see the search bar anymore?
If the delegate methods are not being called it means that the UISearchBar doesn't know where to delegate the optional methods in UISearchBarDelegate protocol.
So the ViewController that implements these methods
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
NSLog(#"searching");
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(#"Text change");
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Cancel clicked");
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Search Clicked");
}
must be set as the delegate of the UISearchBar. To make sure that the correct ViewController is set as the delegate of the UISearchBar I would print the
[searchBar.delegate class]
If this returns nil or some other class name then the one you expect, you will know where the problems comes from.
Hope this helps.
UPDATE
Ok, I just created a Single View Application and dragged a UISearchBar on the storyboard. Then I added an outlet for the UISearchBar called searchBar. Then I made the ViewController implement the UISearchBarDelegate protocol. Then in ViewDidLoad I set the searchBar.delegate = self. After I added all the delegate methods listed above everything worked... So the only thing that I can think of now is that the ViewController is not implementing the protocol
#interface ViewController () <UISearchBarDelegate>
Here's the ViewController source code:
#import "ViewController.h"
#interface ViewController () <UISearchBarDelegate>
#property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.searchBar.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UISearchBarDelegate
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
NSLog(#"searching");
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(#"Text change");
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Cancel clicked");
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Search Clicked");
}
I am using a searchBar wherein the cancel button of searchBar when clicked should remove the keyboard. I tried using resignFirstResponder but thats not working at all. Does anyone have any other way out for it?
use this line, it will help you
[self.view endEditing:YES];
Without any code in OP, try this:
[self.view endEditing:YES];
You'll need one/all of these methods:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
[searchBar resignFirstResponder];
}
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
this test code it work 1000%.
In your .h file
#interface ViewController : UIViewController<UISearchBarDelegate>
set delegate in your viewDidLoad method
#property (strong, nonatomic) UISearchBar *searchBar;
- (void)viewDidLoad
{
[super viewDidLoad];
[self.searchBar setDelegate:self];
}
-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
[self.searchBar setShowsCancelButton:YES];
return YES;
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
searchBar.text = #"";
[searchBar resignFirstResponder];
}
I am seeing a bug where my app crashes if I click the back button in a navigation controller while editing a UISearchBar embedded as the titleView of the UINavigationBar. The main VC is a UITableViewController that is pushed onto the view stack using [parentView.navigationController pushViewController:myTableView animated:YES];
Here is the code I use to create the UISearchBar in my viewDidLoad:
UISearchBar *customSearch = [[UISearchBar alloc] initWithFrame:
CGRectMake(0,0, 320, 44)];
customSearch.delegate = self;
customSearch.placeholder = #"Some placeholder text";
self.navigationItem.titleView = customSearch;
These are my delegate implementations for the UISearchBar delegate - handle search just updates the array backing the tableView and calls [self.tableview reloadData]:
- (void) searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
searchBar.showsCancelButton = YES;
}
- (void) searchBarTextDidEndEditing:(UISearchBar *)searchBar {
searchBar.showsCancelButton = NO;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self handleSearch:searchBar];
[searchBar resignFirstResponder];
}
- (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[self handleSearch:searchBar];
}
- (void)handleSearch:(UISearchBar *)searchBar {
[self updateFilteredData:searchBar.text];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar {
searchBar.text = #"";
[self handleSearch:searchBar];
[searchBar resignFirstResponder];
}
I don't get any information from the crash - just a sigkill. If I'm not editing the UISearchBar it works fine. I've tried resigning the first responder and it still crashes.
Update - adding filtered data
- (void) updateFilteredData: (NSString *) nameFilter {
if (nameFilter.length) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(first_name CONTAINS[cd] %#) OR (last_name CONTAINS[cd] %#)", nameFilter, nameFilter];
self.filteredData = [self.data filteredArrayUsingPredicate:predicate];
} else {
self.filteredData = self.data;
}
[self.tableView reloadData];
}
I've tried all of the following + all of them together in viewWillDisappear. They all run successfully and the searchBar reference is to a valid UISearchBar.
-(void)viewWillDisappear:(BOOL)animated {
UISearchBar *mySearchBar = (UISearchBar *)self.navigationItem.titleView;
[mySearchBar resignFirstResponder];
mySearchBar.delegate = nil;
self.navigationItem.titleView = nil;
for (UIView *view in [mySearchBar subviews] ) {
[view removeFromSuperview];
}
[mySearchBar removeFromSuperview];
[super viewWillDisappear:animated];
}
It may not be a search bar thing, I just see the crash consistently when I'm editing the search bar - It could be something with the view hiding the keyboard and trying to redraw the cells below at the same time the TableView is being deconstructed.