I created a search bar at the header view of a table:
self.searchResults = [NSMutableArray arrayWithCapacity:[self.list count]];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.searchBar.barTintColor = [UIColor clearColor];
self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);
[[UIBarButtonItem appearanceWhenContainedIn: [UISearchBar class], nil] setTintColor:[UIColor whiteColor]];
[self.searchController.searchBar becomeFirstResponder];
And when tap a certain row in the tableview, a new view controller will be pushed.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"HEY ROW %ld", indexPath.row+1);
ZLContainerViewController *controller = [[ZLContainerViewController alloc]init]; // a container for UIPage
[self.navigationController pushViewController:controller animated:YES];
}
However, after pushing the new view controller, the search bar is still there. How can I solve this problem?
Any suggestion is much appreciated!
Use the below code in viewDidLoad.
Swift:
self.definesPresentationContext = true
Objective-C:
self.definesPresentationContext = YES;
This solved the problem for me.
One of these two UISearchBarDelegate delegate methods should fix your problem
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
return YES;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self.searchBar resignFirstResponder];
}
Related
I have put a table view in a view controller containing a list of items.
[In that i had put one search icon in navigation bar shown in first image.When i click on that icon a search bar opens and a cancel button will be shown.Cancel button is working.][1]
Now i want to do search in search box.Please anyone can help me to get the code for that.
In viewDidLoad:
UIBarButtonItem *searchButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:#selector(toggleSearch:)];
self.navigationController.navigationBar.topItem.rightBarButtonItem = searchButton;
toggleSearch:
- (IBAction)toggleSearch:(id)sender
{
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
_searchBar.delegate=self;
[_searchBar sizeToFit];
searchController= [[UISearchController alloc]initWithSearchResultsController:self];
searchController.searchResultsUpdater = self;
searchController.searchResultsUpdater = self;
searchController.delegate = self;
self.navigationItem.titleView = searchController.searchBar;
searchController.hidesNavigationBarDuringPresentation = NO;
}
You need to implement searchbar delegate methods.
First you can assign your main array to temporary array and after that you can add this code.
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
[_searchBar setShowsCancelButton:YES animated:YES];
return YES;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate *result=[NSPredicate predicateWithFormat:#"SELF CONTAINS[cd] %#",searchText];
NSArray * array = [arrTemp filteredArrayUsingPredicate:result];
arrMain=[array mutableCopy];
[tblview reloadData];
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[_searchBar setShowsCancelButton:NO animated:YES];
}
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
NSPredicate *result=[NSPredicate predicateWithFormat:#"SELF CONTAINS[cd] %#",searchBar.text];
NSArray * array = [arrTemp filteredArrayUsingPredicate:result];
arrMain=[array mutableCopy];
[tblview reloadData];
[searchBar resignFirstResponder];
[_searchBar setShowsCancelButton:NO animated:YES];
}
The behaviour different between automatic presentation UISearchController and present the search controller myself.
#implementation MyViewComtroller
// click search barbutton on right of navigationBar
- (void)searchAction:(id)sender {
ArticleSearchViewController *searchResultsController = [[ArticleSearchViewController alloc] init];
UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
searchController.searchResultsUpdater = searchResultsController;
searchController.searchBar.delegate = searchResultsController;
searchController.delegate = searchResultsController;
searchController.hidesNavigationBarDuringPresentation = NO;
[self presentViewController:searchController animated:YES completion:nil];
}
#end
#implementation ArticleSearchViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
ArticleDetailController * articleDetailController = [ArticleDetailController new];
[(UINavigationController *)self.presentingViewController pushViewController:articleDetailController animated:YES];
}
#end
The push action happend below UISearchController.
You are presenting the search controller in wrong way. Look at part of the documentation.
You use a search controller in tandem with your existing view
controllers. When you have a view controller with searchable content,
incorporate the search bar of a UISearchController object into your
view controller’s interface. When the user interacts with that search
bar, the search controller automatically displays a new view
controller with the search results that you specify.
Instead of this in your main controller:
[self presentViewController:searchController animated:YES completion:nil];
You should do this on iOS 11:
self.definesPresentationContext = YES;
self.navigationItem.searchController = searchController;
Or this on pre iOS 11:
self.definesPresentationContext = YES;
self.navigationItem.titleView = searchController.searchBar;
Or place anywhere else the searchController.searchBar in your presented view hierarchy.
You should also setup the search controller in a place like viewDidLoad and not on a button press.
And the way you are getting a reference to your navigationController in ArticleSearchViewController has to be updated to something like:
[self.presentingViewController.navigationController pushViewController:articleDetailController animated:YES];
View controller with searchable content:
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor blackColor]];
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ArticleSearchViewController *searchResultsController = [sb instantiateViewControllerWithIdentifier:#"ArticleSearchViewController"];
UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
searchController.searchResultsUpdater = searchResultsController;
searchController.searchBar.delegate = searchResultsController;
searchController.delegate = searchResultsController;
searchController.hidesNavigationBarDuringPresentation = NO;
// [self presentViewController:searchController animated:YES completion:nil]; //WRONG
self.definesPresentationContext = YES;
self.navigationItem.searchController = searchController;
}
#end
Results Controller:
#implementation ArticleSearchViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UIViewController * articleDetailController = [UIViewController new];
[self.presentingViewController.navigationController pushViewController:articleDetailController animated:YES];
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
// update appropriately
}
#end
This is a better answer:
definesPresentationContext = true
just write this in your MyViewController
I am trying to implement a UISearchController in a TableViewController. After i enter the text in the search bar I am getting the count in the console of how many records to display but the tableview is not getting reloaded. Please find the code for the Update Search Results Controller.
- (void)viewDidLoad {
[super viewDidLoad];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.tableView.tableHeaderView = self.searchController.searchBar;
self.definesPresentationContext = YES;
_db=[[Database alloc]init];
if(_vehicles==nil){
_vehicles=[[NSMutableArray alloc]init];
}
_vehicles=[_db getTheData:nil];
NSLog(#"%lu",(unsigned long)_vehicles.count);
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
NSString *searchText = searchController.searchBar.text;
NSMutableArray<Vehicle*> *searchResults = [[NSMutableArray<Vehicle*> alloc]init];
for(Vehicle *v in self.vehicles){
if([v.make containsString:searchText]){
[searchResults addObject:v];
}
}
NSLog(#"%lu",searchResults.count);
VehicleTableViewController *tableController = (VehicleTableViewController *)self.searchController.searchResultsController;
tableController.vehicles = searchResults;
[tableController.tableView reloadData];
}
VehicleTableViewController *tableController = (VehicleTableViewController *)self.searchController.searchResultsController;
This line is wrong I think. searchResultsController is not tableviewctrler. You cannot force it to be one. You already have tableView reference so use that.
[self.tableView reloadData];
Make sure you replace the Table datasource with the searchresult before reloading the table.
[dataSourceArr removeAllObjects];
[dataSourceArr = [NSMutableArray arrayWithArray: searchResults];
I am new to iOS programming.
I have to implement a location search based on the third party map API, but I think I have messed up multiple view controllers.
Scenario:
I have a mapviewController for displaying the mapview. And I have a searchController for searchbar. There is a resultviewController property in searchController for display the search suggestions.
I have tried to add search VC as child VC to map VC, but once I click to the search bar it returns "Application tried to present modally an active controller".
So then I remove search VC from map VC & the search bar is not activated.
Therefore I want to ask how to handle these VCs, and avoid the case that map view covers the search bar and suggestion lists.
Thank you so much.
UPDATE:
I'm building a search bar in code. My aim is to build the following style in iOS.
like this http://i1.tietuku.com/cd4efa23d97af75ft.jpg
I pushed the map viewController to the navigation controller from menu.
[self.navigationController pushViewController:mapviewController animated:YES];
And trying to add a searchController to it.
- (void)viewDidLoad {
[super viewDidLoad];
_resultsTableController = [[UITableViewController alloc] init];
_searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsTableController];
_searchController.searchResultsUpdater = self;
[_searchController.searchBar sizeToFit];
_resultsTableController.tableView.tableHeaderView = _searchController.searchBar;
self.searchController.searchBar.delegate = self;
_resultsTableController.tableView.delegate = self;
_searchController.delegate = self;
_searchController.dimsBackgroundDuringPresentation = NO;
_searchController.searchBar.delegate = self;
mapView = [[BMKMapView alloc]initWithFrame:CGRectMake(0, kHeight(100), kScreen_Width , kScreen_Height-kHeight(100))];
[self addChildViewController:_searchController];
[self.view addSubview: _searchController.view];
[self.view addSubview:mapView];
}
for UISearchController you no need to add it as child view controller and and instant of using UITableViewController uses UITableView it make easy for you and
here below is code that is .m file
free to run that code and without uses storyboard.
#interface ViewController ()
{
UITableView *tableview;
UISearchController *searchcontroller;
NSMutableArray *array;}
#end
#implementation ViewController
(void)viewDidLoad
{
[super viewDidLoad];
array = [[NSMutableArray alloc]initWithObjects:#"one",#"two",#"three",#"four", nil];
tableview = [[UITableView alloc]initWithFrame:CGRectMake(0, 50, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)/2)];
[self.view addSubview:tableview];
tableview.dataSource = self;
tableview.delegate =self;
searchcontroller = [[UISearchController alloc]initWithSearchResultsController:nil]; // Create Reference of searchController
searchcontroller.searchResultsUpdater = self;
searchcontroller.searchBar.backgroundColor = [UIColor redColor];
searchcontroller.searchBar.barStyle = UIBarStyleBlack;
searchcontroller.searchBar.barTintColor = [UIColor whiteColor];
searchcontroller.dimsBackgroundDuringPresentation = false;
[searchcontroller.searchBar sizeToFit];
tableview.tableHeaderView = searchcontroller.searchBar;
MKMapView *mapview = [[MKMapView alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(tableview.frame), CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)/2)];
[self.view addSubview:mapview];
}
(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController;
{
NSLog(#"update ");
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
// Default is 1 if not implemented
{
return 1;
}
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return array.count;
}
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
}
cell.textLabel.text = array[indexPath.row];
return cell;
}
According to me you should use only one view controller which has a map on it. Over the map you can simply add custom search view and on typing/ taping search you can show search results using UITableview with some dropping animation keeping some max frame fixed, And finally on taping any result remove this UITableView and show location of map. If time permits I will create a sample for you, cant give assurance but will try. Mean while you can also go through Maps reference may be helpful
I have a UITableViewController and I want a UISearchBar on the top so I use
viewForHeaderInSection: delegate method because when I scroll I don't want to hide the UISearchBar. The problem is (only iOS7) that when I press cancel button the UISearchBar disappears.
here is some code:
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:UITableViewStylePlain];
if (self) {
// Custom initialization
self.filteredListContent = [[NSMutableArray alloc] init];
mySearchBar = [[UISearchBar alloc] init];
mySearchBar.delegate = self;
[mySearchBar setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[mySearchBar sizeToFit];
searchDisplayController = [[UISearchDisplayController alloc]initWithSearchBar:mySearchBar contentsController:self];
[searchDisplayController setDelegate:self];
[self setSearchDisplayController:searchDisplayController];
[searchDisplayController setSearchResultsDataSource:self];
self.tableView.scrollEnabled = YES;
}
return self;
}
Then I return mySearchBar on viewForHeaderInSection: delegate method.
What's wrong with that?