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.
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];
}
I recently followed one git hub project for Collection view search bar.In that there is a search bar, collection view cell .All working well in potrait mode. When i use landscape mode to see, the screen search bar alone showing half -width size.Here is the search bar code .I use programatically to add search bar.
NOTE: I am using deployment target 7.0 should run in all version of ios 7,8,9 devices.
How to make my search bar with same width & height with full width in landscape mode.
My code:
#import "CollectionViewController.h"
#import "CollectionViewCell.h"
#interface CollectionViewController ()<UISearchBarDelegate>
#property (nonatomic,strong) NSArray *dataSource;
#property (nonatomic,strong) NSArray *dataSourceForSearchResult;
#property (nonatomic) BOOL searchBarActive;
#property (nonatomic) float searchBarBoundsY;
#property (nonatomic,strong) UISearchBar *searchBar;
#property (nonatomic,strong) UIRefreshControl *refreshControl;
#end
#implementation CollectionViewController
static NSString * const reuseIdentifier = #"Cell";
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// datasource used when user search in collectionView
self.dataSourceForSearchResult = [NSArray new];
// normal datasource
self.dataSource =#[#"Modesto",#"Rebecka",#"Andria",#"Sergio"];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self prepareUI];
}
-(void)dealloc{
// remove Our KVO observer
[self removeObservers];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - actions
-(void)refreashControlAction{
[self cancelSearching];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// stop refreshing after 2 seconds
[self.collectionView reloadData];
[self.refreshControl endRefreshing];
});
}
#pragma mark - <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (self.searchBarActive) {
return self.dataSourceForSearchResult.count;
}
return self.dataSource.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
// Configure the cell
if (self.searchBarActive) {
cell.laName.text = self.dataSourceForSearchResult[indexPath.row];
}else{
cell.laName.text = self.dataSource[indexPath.row];
}
return cell;
}
#pragma mark - <UICollectionViewDelegateFlowLayout>
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
insetForSectionAtIndex:(NSInteger)section{
return UIEdgeInsetsMake(self.searchBar.frame.size.height, 0, 0, 0);
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
CGFloat cellLeg = (self.collectionView.frame.size.width/2) - 5;
return CGSizeMake(cellLeg,cellLeg);;
}
#pragma mark - search
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"self contains[c] %#", searchText];
self.dataSourceForSearchResult = [self.dataSource filteredArrayUsingPredicate:resultPredicate];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
// user did type something, check our datasource for text that looks the same
if (searchText.length>0) {
// search and reload data source
self.searchBarActive = YES;
[self filterContentForSearchText:searchText
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
[self.collectionView reloadData];
}else{
// if text lenght == 0
// we will consider the searchbar is not active
self.searchBarActive = NO;
}
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
[self cancelSearching];
[self.collectionView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
self.searchBarActive = YES;
[self.view endEditing:YES];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
// we used here to set self.searchBarActive = YES
// but we'll not do that any more... it made problems
// it's better to set self.searchBarActive = YES when user typed something
[self.searchBar setShowsCancelButton:YES animated:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
// this method is being called when search btn in the keyboard tapped
// we set searchBarActive = NO
// but no need to reloadCollectionView
self.searchBarActive = NO;
[self.searchBar setShowsCancelButton:NO animated:YES];
}
-(void)cancelSearching{
self.searchBarActive = NO;
[self.searchBar resignFirstResponder];
self.searchBar.text = #"";
}
#pragma mark - prepareVC
-(void)prepareUI{
[self addSearchBar];
[self addRefreshControl];
}
-(void)addSearchBar{
if (!self.searchBar) {
self.searchBarBoundsY = self.navigationController.navigationBar.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height;
self.searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,self.searchBarBoundsY, [UIScreen mainScreen].bounds.size.width, 44)];
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.searchBar.tintColor = [UIColor whiteColor];
self.searchBar.barTintColor = [UIColor whiteColor];
self.searchBar.delegate = self;
self.searchBar.placeholder = #"search here";
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor whiteColor]];
// add KVO observer.. so we will be informed when user scroll colllectionView
[self addObservers];
}
if (![self.searchBar isDescendantOfView:self.view]) {
[self.view addSubview:self.searchBar];
}
}
-(void)addRefreshControl{
if (!self.refreshControl) {
self.refreshControl = [UIRefreshControl new];
self.refreshControl.tintColor = [UIColor whiteColor];
[self.refreshControl addTarget:self
action:#selector(refreashControlAction)
forControlEvents:UIControlEventValueChanged];
}
if (![self.refreshControl isDescendantOfView:self.collectionView]) {
[self.collectionView addSubview:self.refreshControl];
}
}
-(void)startRefreshControl{
if (!self.refreshControl.refreshing) {
[self.refreshControl beginRefreshing];
}
}
#pragma mark - observer
- (void)addObservers{
[self.collectionView addObserver:self forKeyPath:#"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
- (void)removeObservers{
[self.collectionView removeObserver:self forKeyPath:#"contentOffset" context:Nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(UICollectionView *)object change:(NSDictionary *)change context:(void *)context{
if ([keyPath isEqualToString:#"contentOffset"] && object == self.collectionView ) {
self.searchBar.frame = CGRectMake(self.searchBar.frame.origin.x,
self.searchBarBoundsY + ((-1* object.contentOffset.y)-self.searchBarBoundsY),
self.searchBar.frame.size.width,
self.searchBar.frame.size.height);
}
}
Also Get full project here Git-hub
Here the portrait mode image:
This same search bar when i run in landscape my search bar is in half with like this:
What code i need to add to set my search bar with full-width view in landscape mode.Thnaks!
I have used your project in github. Lets make the changes to work full search bar in landscape mode: Replace the below code as it as in your addsearchbar method :
-(void)addSearchBar{
if (!self.searchBar) {
self.searchBarBoundsY = self.navigationController.navigationBar.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height;
self.searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,self.searchBarBoundsY, [UIScreen mainScreen].bounds.size.width, 44)];
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.searchBar.tintColor = [UIColor whiteColor];
self.searchBar.barTintColor = [UIColor whiteColor];
self.searchBar.delegate = self;
self.searchBar.placeholder = #"search here";
// added line-to set your screen fit and autoresizing with width and bottom margin.You can also add any position to that
[self.searchBar sizeToFit];
_searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleBottomMargin;
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor whiteColor]];
// add KVO observer.. so we will be informed when user scroll colllectionView
[self addObservers];
}
if (![self.searchBar isDescendantOfView:self.view]) {
[self.view addSubview:self.searchBar];
}
}
Hope this help !
Try doing the following when your view loads or appears:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:[UIDevice currentDevice]];
Then add the following method in your View Controller :
- (void) orientationChanged:(NSNotification *)note
{
CGRect frame = _searchBar.frame;
frame.size.width = self.view.frame.size.width;
_searchBar.frame = frame;
}
Here's what's happening:
The user clicks search and sees the following image:
Then the user starts typing in a term and as soon as that happens the NavigationBar disappears. What you're looking at here is an empty space where the Navigation Bar was attached. I've tried everything and cannot figure out why it's doing this. And no the ViewController is not a root view to a NavigationController (THERE IS NO UINavigationController).
Here's the relevant code for my search delegate:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
if ([searchText length] == 0)
{
[self.aTableView reloadData];
return;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.title contains[cd] %# OR SELF.summary contains[cd] %#", searchText, searchText];
mFilteredArray_ = [[self.parseResultsCanadaSection filteredArrayUsingPredicate:predicate] copy];
[self.aTableView reloadData];
}
#pragma mark - UISearchDisplayController delegate methods
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
mFilteredArray_ = nil;
[self.aTableView reloadData];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
mFilteredArray_ = nil;
[self.aTableView reloadData];
}
Try setting the frame of the search Bar to animate up the screen when the user begins searching, that is how I solved this.
-(void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
if (isIOSseven) {
searching = YES;
[UIView animateWithDuration:0.25 animations:^{
searchBar.frame = CGRectMake(searchBar.frame.origin.x, 20, searchBar.frame.size.width, searchBar.frame.size.height);
tableView.frame = CGRectMake(tableView.frame.origin.x, searchBar.frame.origin.y + searchBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height - 40);
}];
}
}
-(void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
if (isIOSseven) {
searching = NO;
[UIView animateWithDuration:0.25 animations:^{
searchBar.frame = CGRectMake(searchBar.frame.origin.x, 64, searchBar.frame.size.width, searchBar.frame.size.height);
tableView.frame = CGRectMake(0, searchBar.frame.origin.y + searchBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height - 64);
}];
}
The way I solved this was to add a UINavigationController. It seemed like the only way to properly solve this issue.
I am using a UISearchBar to search a list, but when I click on the search button
on the keyboard, the keyboard does not hide.
Please help me to fix this issue.
Here is my code
-(void)search:(UISearchBar*)searchbar Text:(NSString*)text
{
[copyListOfItems removeAllObjects];
if([text length] > 0) {
// [ovController.view removeFromSuperview];
searching = YES;
NSString *searchText = searchBar.text;
for(imergencyData *objtrust in aryTrustee)
{
NSRange titleResultsRange = [objtrust.strName rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[copyListOfItems addObject:objtrust];
}
NSLog(#"number of object found %d",copyListOfItems.count);
}
else
{
// [tblTrustee insertSubview:ovController.view aboveSubview:self.parentViewController.view];
[searchbar resignFirstResponder];
searching = NO;
//tblTrustee.scrollEnabled = NO;
}
[tblTrustee reloadData];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)aSearchBar
{
[aSearchBar resignFirstResponder];
[self.view endEditing:YES];
}
//Method call when type text in search box
-(void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {
[self search:theSearchBar Text:searchText];
}
//method call when on search button
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBa{
[searchBa endEditing:YES];
[searchBa resignFirstResponder];
[self search:searchBa Text:searchBar.text];
}
put this line of code and try it once,
- (void)searchBarTextDidEndEditing:(UISearchBar *)aSearchBar {
[aSearchBar resignFirstResponder];
[self.view endEditing:YES];
}
(or)
EDIT:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
[searchBar resignFirstResponder];
[self.view endEditing:YES];
}
Set first searchbar.delegate = self then in - (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar call [searchbar resignFirstRespnder]
Good Luck
You can use below delegate which is called when searchbar Search button is clicked.
- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar
{
[theSearchBar resignFirstResponder];
}
Or use this as :
- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar
{
[self keyBoradRemove];
}
- (void) keyBoradRemove
{
searchBar.text = #"";
[searchBar resignFirstResponder];
}
here searchBar is an instance of UISearchBar.
UISearchBar *searchBar;
Hope it helps you.
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
use search bar delegate as
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar1
{
[searchBar1 resignFirstResponder];
}
use this code for hide keyboard on click of search button of keyboard
- (void)searchBarTextDidBeginEditing:(UISearchBar *) bar
{
UITextField *searchBarTextField = nil;
NSArray *views = ([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f) ? bar.subviews : [[bar.subviews objectAtIndex:0] subviews];
for (UIView *subview in views)
{
if ([subview isKindOfClass:[UITextField class]])
{
searchBarTextField = (UITextField *)subview;
break;
}
}
searchBarTextField.enablesReturnKeyAutomatically = NO;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
But before that kindly check whether you have set the search bar delegate properly.
for swift 1.2 you can touch outside or click search , in both cases keyboard will hide
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
After I clicked the cancel button the scope bar stands alongside the search bar ... but the code is:
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
searchBar.showsScopeBar = YES;
[searchBar sizeToFit];
[searchBar invalidateIntrinsicContentSize];
[searchBar setShowsCancelButton:YES animated:YES];
tabellaCanzoni.tableHeaderView = self.searchDisplayController.searchBar;
}
I want it to stay below the search, not alongside!
With this code all working right:
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[_barraRicerca resignFirstResponder];
_barraRicerca.text = nil;
[_barraRicerca setShowsScopeBar:YES];
[_barraRicerca sizeToFit];
isFiltered=FALSE;
[tabellaVideo reloadData];
}