here my code in view controller.h
#import "AppDelegate.h"
#interface SearchRsultsFanSideViewController : UIViewController<UISearchBarDelegate,UISearchDisplayDelegate>
{
}
#property (strong, nonatomic) IBOutlet UISearchBar *searchData;
#property (strong, nonatomic) UISearchDisplayController *controller;
in viewcontroller.m
- (void)viewDidLoad
{
[super viewDidLoad];
searchResults=[[NSArray alloc]init];
self.controller = [[UISearchDisplayController alloc]initWithSearchBar:searchData contentsController:self];
self.controller.searchResultsDataSource = self;
self.controller.searchResultsDelegate = self;
}
delegate method for UIsearchbar
#pragma Mark - SearchBar Delegate
- (void)filterData
{
searchResults = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains [cd] %#", searchData.text];
NSArray *arrayaaa=[finalArray copy];
NSLog(#"The result Datas==%#",arrayaaa);
searchResults = [[arrayaaa filteredArrayUsingPredicate:predicate] mutableCopy];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[self.searchDisplayController setActive:YES];
[self filterData];
}
try this
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller{
[controller.searchBar setFrame:CGRectMake(44, 0, 320 - 44, 43)];
[self.searchDisplayController.searchResultsTableView setDelegate:self];
}
Try this:
-(void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.searchDisplayController.isActive) {
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
}
Related
I added UISearchBar in UITableView and than added it inside UIView. I'm adding UIView on window and everything works fine. searchBarShouldBeginEditing is triggering and displaying logs however, searchBarTextDidBeginEditing is not triggering. Below is my code:
AppDelegate *appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
self.frame = appDelegate.window.frame;
[appDelegate.window addSubview:self];
inside myView.h:
#property(strong, nonatomic) UISearchController *searchController;
and inside myView.m:
- (void)drawRect:(CGRect)rect {
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
[self.searchController.searchBar sizeToFit];
self.searchController.searchBar.userInteractionEnabled = YES;
tblDropdown.tableHeaderView = self.searchController.searchBar;
arrSeached = [NSMutableArray array];
}
Maybe, the problem is that your view controller or view (I do know without all code) has not added the protocol correctly.
Anyway, this is a example using UISearchController:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating>
#property (nonatomic, weak) IBOutlet UITableView * tableView;
#property (nonatomic, strong) UISearchController * searchController;
#property (nonatomic, strong) NSMutableArray * allItems;
#property (nonatomic, strong) NSMutableArray * filteredItems;
#property (nonatomic, weak) NSArray * displayedItems;
#end
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize tableView;
#synthesize searchController;
#synthesize allItems;
#synthesize displayedItems;
#synthesize filteredItems;
- (void)viewDidLoad {
[super viewDidLoad];
// Create a list
self.allItems = [[NSMutableArray alloc] init];
[self.allItems addObject:#"One"];
[self.allItems addObject:#"Two"];
[self.allItems addObject:#"Three"];
// Create a list to hold search results (filtered list)
self.filteredItems = [[NSMutableArray alloc] init];
// Initially display the full list. This variable will toggle between the full and the filtered lists.
self.displayedItems = self.allItems;
// Here's where we create our UISearchController
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.delegate = self;
[self.searchController.searchBar sizeToFit];
// Add the UISearchBar to the top header of the table view
self.tableView.tableHeaderView = self.searchController.searchBar;
// Hides search bar initially. When the user pulls down on the list, the search bar is revealed.
[self.tableView setContentOffset:CGPointMake(0, self.searchController.searchBar.frame.size.height)];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
return [self.displayedItems count];
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)anIndexPath {
UITableViewCell * cell = [aTableView dequeueReusableCellWithIdentifier:#"FruitCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] init];
}
cell.textLabel.text = [self.displayedItems objectAtIndex:anIndexPath.row];
return cell;
}
// When the user types in the search bar, this method gets called.
- (void)updateSearchResultsForSearchController:(UISearchController *)aSearchController {
NSLog(#"updateSearchResultsForSearchController");
NSString *searchString = aSearchController.searchBar.text;
NSLog(#"searchString=%#", searchString);
// Check if the user cancelled or deleted the search term so we can display the full list instead.
if (![searchString isEqualToString:#""]) {
[self.filteredItems removeAllObjects];
for (NSString *str in self.allItems) {
if ([searchString isEqualToString:#""] || [str localizedCaseInsensitiveContainsString:searchString] == YES) {
NSLog(#"str=%#", str);
[self.filteredItems addObject:str];
}
}
self.displayedItems = self.filteredItems;
}
else {
self.displayedItems = self.allItems;
}
[self.tableView reloadData];
}
#end
I'm trying to add a UISearchBar to a UITableView but the method TextDidBeginEditing is not being called. I think I am missing something simple but I can't figure it out.
Header File:
#interface TableViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>
#property (nonatomic, strong) NSMutableArray *initialCities;
#property (nonatomic, strong) NSMutableArray *filteredCities;
#property (nonatomic, strong) UISearchBar *searchBar;
#property BOOL isFiltered;
#end
Implementation File:
#import "TableViewController.h"
#interface TableViewController ()
#end
#implementation TableViewController
#synthesize initialCities, filteredCities, isFiltered, searchBar;
- (void)loadView
{
[super loadView];
searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 44.0)];
searchBar.delegate = self;
searchBar.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.tableView.tableHeaderView = searchBar;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.tableView.delegate = self;
initialCities = [[NSMutableArray alloc] initWithObjects:#"London", #"New York", #"Berlin", nil];
}
#pragma mark - UITableView DataSource Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (isFiltered == YES)
{
return filteredCities.count;
}
else
{
return initialCities.count;
}
}
- (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];
}
if (isFiltered == YES)
{
cell.textLabel.text = [filteredCities objectAtIndex:indexPath.row];
}
else
{
cell.textLabel.text = [initialCities objectAtIndex:indexPath.row];
}
return cell;
}
#pragma mark - UITableView Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
#pragma mark - UISearchBar Delegate methods
- (void)searchBar:(UISearchBar *)searchBar TextDidBeginEditing:(NSString *)searchText
{
searchBar.showsCancelButton = YES;
if (searchText.length == 0)
{
isFiltered = NO;
}
else
{
isFiltered = YES;
filteredCities = [[NSMutableArray alloc] init];
for (NSString *cityName in initialCities)
{
NSRange cityNameRange = [cityName rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (cityNameRange.location != NSNotFound)
{
[filteredCities addObject:cityName];
}
}
}
[self.tableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The result is that the search bar is displayed, the table view is displayed, but when I type text into the search bar the table view is not filtered. There is no crash. Any help is appreciated. Thank you.
Try this
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)searchText
{
// Your filter code
}
The method you implemented is not even present in Protocol
– searchBar:textDidChange:
– searchBar:shouldChangeTextInRange:replacementText:
– searchBarShouldBeginEditing:
– searchBarTextDidBeginEditing:
– searchBarShouldEndEditing:
– searchBarTextDidEndEditing:
(void)searchBar:(UISearchBar *)searchBar TextDidBeginEditing:(NSString *)searchText
This method is not existed in searchBar's delegate.
Use searchBarTextDidBeginEditing.
Go through this tutorial. well explained.
http://www.appcoda.com/search-bar-tutorial-ios7/
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
searchResults = [actualData filteredArrayUsingPredicate:resultPredicate];
}
I have a root view controller which composes a search bar on the top and a child table view controller on the bottom. I used composition instead of assigning the search bar to the table view's header for these reasons:
I didn't want the index to overlap with the search bar (like Contacts app).
I wanted the search bar to be sticky. That is, it doesn't move when I scroll the table view (again like the Contacts app).
My table view already had a header.
Since the search bar is in the root view controller, I instantiate my search display controller in the root view controller also. There are two problems with the search UI for which I seek advice:
The translucent gray overlay does not cover the entire child table view. It leaves the top portion of the header and the index visible.
Likewise, the search results table does not cover the entirety of the child table view. I know how to manually change the frame of this results table view, but doing so only fixes just that ... the gray translucent overlay's frame is not linked to the results table view frame. Their is no property to access the overlay.
1) Idle
2) Enter Search Bar
3) Start Typing
#import "ContactsRootViewController.h"
#import "ContactsViewController.h"
#import "UIView+position.h"
#import "User.h"
#import "UserCellView.h"
#import "UserViewController.h"
#interface ContactsRootViewController ()
#property(nonatomic, strong) UISearchBar* searchBar;
#property(nonatomic, strong) ContactsViewController* contactsViewController;
#property(nonatomic, strong) UISearchDisplayController* searchController;
#property(nonatomic, strong) NSMutableArray* matchedUsers;
#end
#implementation ContactsRootViewController
#pragma mark UIViewController
- (NSString*)title
{
return #"Contacts";
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.matchedUsers = [NSMutableArray array];
self.searchBar = [[UISearchBar alloc] init];
self.searchBar.placeholder = #"Search";
[self.searchBar sizeToFit];
[self.view addSubview:self.searchBar];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.contactsViewController == nil) {
self.contactsViewController = [[ContactsViewController alloc] init];
[self addChildViewController:self.contactsViewController];
self.contactsViewController.view.frame = CGRectMake(
0.0,
self.searchBar.bottomY,
self.view.frame.size.width,
self.view.frame.size.height - self.searchBar.bottomY
);
self.contactsViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
[self.view addSubview:self.contactsViewController.view];
[self.contactsViewController didMoveToParentViewController:self];
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self.contactsViewController];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
}
}
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.matchedUsers.count;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* identifier = #"contactsRootViewUserCell";
UserCellView* cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UserCellView alloc] initWithIdentifier:identifier];
}
cell.user = [self.matchedUsers objectAtIndex:indexPath.row];
return cell;
}
#pragma mark UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.navigationController pushViewController:[[UserViewController alloc] initWithUser:[self.matchedUsers objectAtIndex:indexPath.row]] animated:YES];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [UserCellView height];
}
#pragma mark UISearchDisplayControllerDelegate
- (BOOL)searchDisplayController:(UISearchDisplayController*)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self.matchedUsers removeAllObjects];
searchString = [searchString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (searchString.length > 0) {
for (User* user in self.contactsViewController.allUsers) {
NSRange match = [user.userDisplayName rangeOfString:searchString options:NSCaseInsensitiveSearch];
if (match.location != NSNotFound) {
[self.matchedUsers addObject:user];
}
}
}
return YES;
}
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
[self.searchBar resignFirstResponder];
}
#end
I re-implemented UISearchDisplayController, calling my implementation SearchController. It does the same thing and has similar delegate callbacks, but the frame of the search results can be controlled by the programmer.
Header
#import <Foundation/Foundation.h>
#class SearchController;
#protocol SearchControllerDelegate <NSObject>
#required
- (BOOL)searchController:(SearchController*)controller shouldReloadTableForSearchString:(NSString*)searchText;
#optional
- (void)searchController:(SearchController*)controller didShowSearchResultsTableView:(UITableView*)tableView;
- (void)searchController:(SearchController *)controller didHideSearchResultsTableView:(UITableView *)tableView;
- (void)searchControllerDidBeginSearch:(SearchController*)controller;
- (void)searchControllerDidEndSearch:(SearchController*)controller;
#end
#interface SearchController : UIViewController <UISearchBarDelegate>
#property(nonatomic, weak) NSObject<SearchControllerDelegate>* delegate;
#property(nonatomic, weak) NSObject<UITableViewDataSource>* searchResultsDataSource;
#property(nonatomic, weak) NSObject<UITableViewDelegate>* searchResultsDelegate;
#property(nonatomic, strong, readonly) UITableView* searchResultsTableView;
- (id)initWithSearchBar:(UISearchBar*)searchBar;
#end
Implementation
#import "SearchController.h"
#import "UIView+position.h"
#interface SearchController ()
#property(nonatomic, strong) UISearchBar* searchBar;
#property(nonatomic, strong) UIButton* searchResultsVeil;
#property(nonatomic, strong, readwrite) UITableView* searchResultsTableView;
#property(nonatomic, assign) BOOL searchResultsTableViewHidden;
- (void)didTapSearchResultsVeil;
- (void)hideSearchResults;
#end
#implementation SearchController
#pragma mark UIViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.searchResultsTableView deselectRowAtIndexPath:[self.searchResultsTableView indexPathForSelectedRow] animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.userInteractionEnabled = NO;
}
#pragma mark SearchController ()
- (void)hideSearchResults
{
self.searchBar.text = nil;
[self.searchResultsTableView reloadData];
self.searchResultsTableViewHidden = YES;
[self.searchBar resignFirstResponder];
}
- (void)didTapSearchResultsVeil
{
[self hideSearchResults];
}
- (void)setSearchResultsTableViewHidden:(BOOL)searchResultsTableViewHidden
{
if (self.searchResultsTableView != nil) {
if (self.searchResultsTableView.hidden && !searchResultsTableViewHidden) {
self.searchResultsTableView.hidden = searchResultsTableViewHidden;
if ([self.delegate respondsToSelector:#selector(searchController:didShowSearchResultsTableView:)]) {
[self.delegate searchController:self didShowSearchResultsTableView:self.searchResultsTableView];
}
} else if (!self.searchResultsTableView.hidden && searchResultsTableViewHidden) {
self.searchResultsTableView.hidden = searchResultsTableViewHidden;
if ([self.delegate respondsToSelector:#selector(searchController:didHideSearchResultsTableView:)]) {
[self.delegate searchController:self didHideSearchResultsTableView:self.searchResultsTableView];
}
}
}
}
- (BOOL)searchResultsTableViewHidden
{
return self.searchResultsTableView == nil || self.searchResultsTableView.hidden;
}
#pragma mark SearchController
- (id)initWithSearchBar:(UISearchBar *)searchBar
{
if (self = [super init]) {
self.searchBar = searchBar;
self.searchBar.delegate = self;
}
return self;
}
- (void)setSearchResultsDataSource:(NSObject<UITableViewDataSource> *)searchResultsDataSource
{
_searchResultsDataSource = searchResultsDataSource;
if (self.searchResultsTableView != nil) {
self.searchResultsTableView.dataSource = searchResultsDataSource;
}
}
- (void)setSearchResultsDelegate:(NSObject<UITableViewDelegate> *)searchResultsDelegate
{
_searchResultsDelegate = searchResultsDelegate;
if (self.searchResultsTableView != nil) {
self.searchResultsTableView.delegate = searchResultsDelegate;
}
}
#pragma mark UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if ([self.delegate searchController:self shouldReloadTableForSearchString:searchText]) {
[self.searchResultsTableView reloadData];
self.searchResultsTableViewHidden = [self.searchResultsTableView.dataSource tableView:self.searchResultsTableView numberOfRowsInSection:0] == 0;
}
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:YES animated:YES];
if (self.searchResultsVeil == nil) {
self.searchResultsVeil = [[UIButton alloc] initWithFrame:self.view.bounds];
self.searchResultsVeil.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.6];
self.searchResultsVeil.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.searchResultsVeil addTarget:self action:#selector(didTapSearchResultsVeil) forControlEvents:UIControlEventTouchUpInside];
self.searchResultsTableView = [[UITableView alloc] initWithFrame:self.searchResultsVeil.bounds style:UITableViewStylePlain];
self.searchResultsTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
if ([self.searchResultsTableView respondsToSelector:#selector(setSeparatorInset:)]) {
self.searchResultsTableView.separatorInset = UIEdgeInsetsMake(
0.0,
self.searchResultsTableView.width,
0.0,
0.0
);
}
self.searchResultsTableViewHidden = YES;
if (self.searchResultsDataSource != nil) {
self.searchResultsTableView.dataSource = self.searchResultsDataSource;
}
if (self.searchResultsDelegate != nil) {
self.searchResultsTableView.delegate = self.searchResultsDelegate;
}
[self.view addSubview:self.searchResultsVeil];
[self.searchResultsVeil addSubview:self.searchResultsTableView];
}
self.view.userInteractionEnabled = YES;
self.searchResultsVeil.hidden = NO;
if ([self.delegate respondsToSelector:#selector(searchControllerDidBeginSearch:)]) {
[self.delegate searchControllerDidBeginSearch:self];
}
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:NO animated:YES];
self.view.userInteractionEnabled = NO;
self.searchResultsVeil.hidden = YES;
if ([self.delegate respondsToSelector:#selector(searchControllerDidEndSearch:)]) {
[self.delegate searchControllerDidEndSearch:self];
}
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[self hideSearchResults];
}
#end
Usage
self.searchController = [[SearchController alloc] initWithSearchBar:self.searchBar];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
[self addChildViewController:self.searchController];
self.searchController.view.frame = CGRectMake(
self.searchBar.x,
self.searchBar.bottomY,
self.searchBar.width,
self.view.height - self.searchBar.bottomY
);
[self.view addSubview:self.searchController.view];
[self.searchController didMoveToParentViewController:self];
It looks like your view controller does not define a presentation context. I had a similar problem and was able to resolve it by setting
self.definesPresentationContext = YES;
in viewDidLoad. According to the documentation this property is
A Boolean value that indicates whether this view controller's view is covered when the view controller or one of its descendants presents a view controller.
I have a UISearchBar added as a subview to a UICollectionView, and attached to a UISearchDisplayController.
I set it up in viewDidLoad:
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar
contentsController:self];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
[self.collectionView addSubview:self.searchBar];
When I push another view controller to the navigation controller then pop it, the search bar disappears. This only happens if the collection view is scrolled down enough for the search bar to be hidden. Also, even though the search bar disappears, tapping the white space where it's supposed to be activates the search display controller attached to it.
This happens only on iOS 7, and if I remove the search display controller the search bar will not disappear.
One more thing worth mentioning. When the search bar has disappeared, if I push another view controller then pop it, the bar will be visible again.
Apparently this is a bug of UISearchDisplayController on iOS 7, so any ideas on how to work around it?
I ended up implementing UISearchDisplayController on my own. Here's my code.
ZBNSearchDisplayController.h
#protocol ZBNSearchDisplayDelegate;
#interface ZBNSearchDisplayController : NSObject<UISearchBarDelegate>
- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController;
- (void)setActive:(BOOL)visible animated:(BOOL)animated;
#property(nonatomic,assign) id<ZBNSearchDisplayDelegate> delegate;
#property(nonatomic, getter = isActive) BOOL active;
#property(nonatomic, readonly) UISearchBar *searchBar;
#property(nonatomic, readonly) UIViewController *searchContentsController;
#property(nonatomic, readonly) UITableView *searchResultsTableView;
#property(nonatomic, assign) id<UITableViewDataSource> searchResultsDataSource;
#property(nonatomic, assign) id<UITableViewDelegate> searchResultsDelegate;
#end
#protocol ZBNSearchDisplayDelegate <NSObject>
#optional
- (void)searchDisplayControllerWillBeginSearch:(ZBNSearchDisplayController *)controller;
- (void)searchDisplayControllerDidBeginSearch:(ZBNSearchDisplayController *)controller;
- (void)searchDisplayControllerWillEndSearch:(ZBNSearchDisplayController *)controller;
- (void)searchDisplayControllerDidEndSearch:(ZBNSearchDisplayController *)controller;
- (void)textDidChange:(NSString *)searchText;
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope;
#end
ZBNSearchDisplayController.m
#import "ZBNSearchDisplayController.h"
#implementation ZBNSearchDisplayController
- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController {
self = [super init];
if (self) {
_searchBar = searchBar;
_searchBar.delegate = self;
_searchContentsController = viewController;
CGFloat y = 64.0f;
CGFloat height = _searchContentsController.view.frame.size.height - y;
_searchResultsTableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, y, _searchContentsController.view.frame.size.width, height)];
_searchResultsTableView.scrollsToTop = NO;
}
return self;
}
- (void)setSearchResultsDataSource:(id<UITableViewDataSource>)searchResultsDataSource {
_searchResultsTableView.dataSource = searchResultsDataSource;
}
- (void)setSearchResultsDelegate:(id<UITableViewDelegate>)searchResultsDelegate {
_searchResultsTableView.delegate = searchResultsDelegate;
}
- (void)setActive:(BOOL)visible animated:(BOOL)animated {
if (!visible) {
[_searchBar resignFirstResponder];
_searchBar.text = nil;
_searchBar.showsCancelButton = NO;
}
if (visible && [self.delegate respondsToSelector:#selector(searchDisplayControllerWillBeginSearch:)]) {
[self.delegate searchDisplayControllerWillBeginSearch:self];
} else if (!visible && [self.delegate respondsToSelector:#selector(searchDisplayControllerWillEndSearch:)]) {
[self.delegate searchDisplayControllerWillEndSearch:self];
}
[_searchContentsController.navigationController setNavigationBarHidden:visible animated:YES];
float alpha = 0;
if (visible) {
[_searchContentsController.view addSubview:_searchResultsTableView];
alpha = 1.0;
}
if ([_searchContentsController.view respondsToSelector:#selector(scrollEnabled)]) {
((UIScrollView *)_searchContentsController.view).scrollEnabled = !visible;
}
if (animated) {
[UIView animateWithDuration:0.2 animations:^{
_searchResultsTableView.alpha = alpha;
} completion:^(BOOL finished) {
self.active = visible;
}];
} else {
_searchResultsTableView.alpha = alpha;
}
}
#pragma mark - UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope {
if ([self.delegate respondsToSelector:#selector(searchBar:selectedScopeButtonIndexDidChange:)]) {
[self.delegate searchBar:searchBar selectedScopeButtonIndexDidChange:selectedScope];
}
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if ([self.delegate respondsToSelector:#selector(textDidChange:)]) {
[self.delegate textDidChange:searchText];
}
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
[searchBar setShowsCancelButton:YES animated:YES];
[self setActive:YES animated:YES];
[_searchResultsTableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[_searchResultsTableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self setActive:NO animated:YES];
[self.searchResultsTableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
}
#end
For some reason [tView reloadData] (where tView is a UITableView) does not refresh my UITableView. cellForRowAtIndexPath, numberOfSectionsInTableView and numberOfRowsInSection only get called once - at load. Those methods don't seem to be called after [tView reloadData]. Here's my code:
(AppDelegate.h):
#import <UIKit/UIKit.h>
#import "MBProgressHUD.h"
#class FirstNavViewController;
#class SecondTableViewController;
#interface <appname>AppDelegate : NSObject <UIApplicationDelegate, MBProgressHUDDelegate> {
UIWindow *window;
UITabBarController *rootController;
FirstNavViewController *viewController;
SecondTableViewController *viewController1;
NSMutableData *responseData;
NSMutableArray *blogEntries;
MBProgressHUD *HUD;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *rootController;
#property (nonatomic, retain) IBOutlet FirstNavViewController *viewController;
#property (nonatomic, retain) IBOutlet SecondTableViewController *viewController1;
#property (nonatomic, retain) NSMutableArray *blogEntries;
#end
(AppDelegate.m):
#import "AppDelegate.h"
#import "FirstNavViewController.h"
#import "SecondTableViewController.h"
#import "SBJson.h"
#define TMP NSTemporaryDirectory()
#implementation AppDelegate
#synthesize window = _window;
#synthesize rootController;
#synthesize viewController;
#synthesize viewController1;
#synthesize blogEntries;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
CGFloat width = self.rootController.view.bounds.size.width;
CGFloat height = self.rootController.view.bounds.size.height;
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, width, height)];
UIImage *imageView = [UIImage imageNamed:#"theme_frame.png"];
UIColor *kMainColor = [[UIColor alloc] initWithPatternImage:imageView];
[v setBackgroundColor:kMainColor];
[kMainColor release];
[self.rootController.tabBar insertSubview:v atIndex:0];
imageView = nil;
[v release];
responseData = [[NSMutableData data] retain];
blogEntries = [NSMutableArray array];
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:#"ENTER_JSON_URL_HERE"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSAssert(nil != self.rootController, #"tab bar controller not hooked up!");
BOOL iPad = NO;
#ifdef UI_USER_INTERFACE_IDIOM
iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
#endif
if (iPad) {
self.viewController = [[[FirstNavViewController alloc] initWithNibName:#"FirstNavViewController_iPad" bundle:nil] autorelease];
self.viewController1 = [[[SecondTableViewController alloc] initWithNibName:#"SecondTableViewController_iPad" bundle:nil] autorelease];
}
else {
self.viewController = [[[FirstNavViewController alloc] initWithNibName:#"FirstNavViewController_iPhone" bundle:nil] autorelease];
self.viewController1 = [[[SecondTableViewController alloc] initWithNibName:#"SecondTableViewController_iPhone" bundle:nil] autorelease];
}
self.rootController.viewControllers = [NSArray arrayWithObject:self.viewController];
self.rootController.selectedIndex = 0;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
self.window.rootViewController = self.rootController;
#else
[self.window addSubview:rootController.view];
#endif
[self.window makeKeyAndVisible];
HUD = [[MBProgressHUD alloc] initWithView:viewController.view];
[viewController.view addSubview:HUD];
[HUD show:NO];
// Regisete for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
HUD.labelText = #"Loading";
return YES;
}
#pragma mark NSURLConnection delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[HUD hide:YES];
[connection release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSMutableArray *allBlogEntries = [responseString JSONValue];
[viewController1 setBlogEntries:allBlogEntries];
[responseString release];
[HUD hide:YES];
}
- (void)dealloc
{
[_window release];
[rootController release];
[viewController release];
[viewController1 release];
[super dealloc];
}
#end
(FirstNavViewController.h):
#import <UIKit/UIKit.h>
#interface FirstNavViewController : UIViewController {
UINavigationController *navController;
}
#property (nonatomic, retain) UINavigationController *navController;
#end
(FirstNavViewController.m):
#import "FirstNavViewController.h"
#import "SecondTableViewController.h"
#implementation FirstNavViewController
#synthesize navController;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
UITabBarItem *tabBarItem = [self tabBarItem];
UIImage *tabBarImage = [UIImage imageNamed:#"blog.png"];
[tabBarItem setImage:tabBarImage];
[tabBarItem setTitle:#"Blog"];
}
return self;
}
- (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.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
navController = [[UINavigationController alloc] initWithRootViewController:self];
SecondTableViewController *secondViewController = [[SecondTableViewController alloc] initWithNibName:#"BlogOverviewViewController_iPhone" bundle:nil];
[navController pushViewController:secondViewController animated:NO];
[blogOverviewViewController release];
[self.view addSubview:navController.view];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
(SecondTableViewController.h):
#import <UIKit/UIKit.h>
#import "SBJson.h"
#interface SecondTableViewController : UIViewController {
NSMutableArray *blogEntries;
IBOutlet UITableView *tView;
}
#property (nonatomic, retain) NSMutableArray *blogEntries;
#property (nonatomic, retain) NSArray *arryData;
#property (nonatomic, retain) IBOutlet UITableView *tView;
#end
(SecondTableViewController.m):
#import "SecondTableViewController.h"
#import "ThirdDetailViewController.h"
#import "NSString+HTML.h"
NSString *convertedString;
#implementation SecondTableViewController
#synthesize arryData;
#synthesize tView;
-(NSMutableArray*)blogEntries {
return [[blogEntries retain] autorelease];
}
-(void)setBlogEntries:(NSMutableArray*)newBlogEntries {
if(newBlogEntries != blogEntries) {
[newBlogEntries retain];
[blogEntries release];
blogEntries = newBlogEntries;
[tView reloadData];
}
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [blogEntries count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
NSDictionary *aBlogEntry = [blogEntries objectAtIndex:[indexPath row]];
NSArray *bPosts = (NSArray *)[aBlogEntry objectForKey:#"posts"];
NSString *stringToConvert = [bPosts valueForKey:#"title_plain"];
NSString *convertedString = [stringToConvert stringByConvertingHTMLToPlainText];
cell.textLabel.text = convertedString;
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.textLabel.font = [UIFont systemFontOfSize:12];
cell.textLabel.minimumFontSize = 10;
cell.textLabel.numberOfLines = 4;
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
NSString *stringToConvert1 = [bPosts valueForKey:#"excerpt"];
NSString *convertedString1 = [stringToConvert1 stringByConvertingHTMLToPlainText];
cell.detailTextLabel.text = convertedString1;
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ThirdDetailViewController *detailViewController = [[ThirdDetailViewController alloc] initWithNibName:#"BlogContentViewController_iPhone" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
NSDictionary *aBlogEntry = [blogEntries objectAtIndex:[indexPath row]];
NSArray *bPosts = (NSArray *)[aBlogEntry objectForKey:#"posts"];
NSString *stringToConvert = [bPosts valueForKey:#"title"];
NSString *convertedString = [stringToConvert stringByConvertingHTMLToPlainText];
[contentViewController changeTitleTextLabel:convertedString];
NSString *stringToConvert1 = [bPosts valueForKey:#"content"];
NSString *convertedString1 = [stringToConvert1 stringByConvertingHTMLToPlainText];
NSString *newConvertedString1 = [convertedString1 stringByReplacingOccurrencesOfString: #"\n" withString:#"\n\n"];
[detailViewController changeContentTextLabel:newConvertedString1];
[tableView deselectRowAtIndexPath: indexPath animated: YES];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (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.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
blogEntries = [[NSMutableArray alloc]init];
self.title = #"Blog";
[self.navigationItem setHidesBackButton:YES animated:NO];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[blogEntries release];
[super dealloc];
}
#end
Does anyone know what the problem is? I am stuck on why the UITableView will not reloadData.
EDIT: Small background: I am using a UITabBarController (AppDelegate) with a UIViewController in it with a UINavigationController as a subview of that UIViewController (FirstNavViewController). The UINavigationController then has a subview with another UIViewController in it. The latter UIViewController (SecondTableViewController) includes a UITableView.
I've just been having this issue. Turned out to be a threading problem for me. For those those who end up here after a search, here is my quick fix:
[tView performSelectorOnMainThread:#selector(reloadData)
withObject:nil
waitUntilDone:false];
It seems reloadData needs to be called on the main thread. I hope this helps (^_^)
In your viewDidLoad method, add: tView.delegate = self;
Your view setup might be the cause of your problems.
I don't really understand the details of your implementation but right now you are adding that SecondTableViewController to both the tab bar controller and then on the stack of a navigation controller in your FistNavViewController viewDidLoad method.
Create the navigation controller with FistNavViewController as its rootViewController, then add the navigation controller as the first view controller to your UITabBarViewController
(code here is typed from memory so please excuse any typos)
FirstNavViewController *vc = [[FirstNavViewController alloc] initWithNibName:#"nibname" andBundleName:nil];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc];
UITabBarController *tbc = [UITabBarController setViewControllers:[NSArray arrayWithObjects:nc, otherVc1Example, otherVc2Example, nil] animated:NO];
In your FirstNavViewController viewDidLoad method, you can then instantiate SecondTableViewController and push it onto the stack with
[self.navigationController pushViewController:secondTableViewController animated:YES];
Finally, within that nav controller you need to make sure you have your UITableView setup correcly either in Interface Builder (by connecting the datasource and delegate outlets to the file owner) or in code by manually setting the tableview delegate and datasource to self.
Bottom line is everything you are trying to do above is WAY easier and less error prone if you use Interface Builder. In MainWindow.xib simple add a tab bar controller and under it add navigation controllers and view controllers as you see fit. It should work "pretty much" out of the box.
Good luck.
Rog