Instagram Explorer Searchbar and Tableview

How to show tableview when user taps searchbar swift

To make the search results of a UISearchController appear in a new UITableView of your choice, do this:

let searchController = UISearchController(searchResultsController: myTableViewController)

instead of this:

let searchController = UISearchController(searchResultsController: nil)

Passing a view controller to the constructor allows the UISearchController to display the view controller at appropriate times (i.e. when the search is active). This is what you need to do.

Passing nil means, I'm using my own view controller (and table view).

Search Bar and Search Display Controller in table view

Well you're on the right track... it is exactly to do with the connection of your controller class to your controller xib.

When you want to initialise a Search Bar and Search Display Controller into a UITableView, you are effectively adding a second table view that, when activated, must be managed by code in your UITableViewController class in the same manner as any UITableView.

I have used these SO questions/answers to check my own answer - I recommend you take a look:

  • Creating a UISearchDisplayController programmatically
  • Gray UISearchBar w/matching scope bar programmatically

I have read the Apple Documentation. I recommend you do the same to help you understand this.

First Step:

You will need to set data source and delegate methods for both table views when you run your controller class.

Before you do any of this, include this property...

@property (nonatomic, strong) UISearchDisplayController *searchController;

The following code describes how to initialise and set the appropriate properties for a UISearchBar and a UISearchDisplayController. If you are programmatically creating a UITableViewController in code you will also need to set the data source and delegate for it (not shown to keep the code easy to read).

You have two options here - which one you choose depends on your code and what you wish to achieve - either set these in your init/awakeFromNib methods, or set these in one of your table view controller (TVC) lifecycle methods.

Option One - Init

(Note1: Paul Hegarty's extraordinary iTunesU lectures taught me to init/awake a class as follows - in this way you are covered for both scenarios - you call init or it can awakeFromNib.)

- (void)setup {
// Provide initialisation code here!!!
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
[searchBar sizeToFit];
[searchBar setDelegate:self];

[self setSearchController:[[UISearchDisplayController alloc] initWithSearchBar:searchBar
contentsController:self]];
[self.searchController setSearchResultsDataSource:self];
[self.searchController setSearchResultsDelegate:self];
[self.searchController setDelegate:self];
}

- (void)awakeFromNib {
[self setup];
}

- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
[self setup];
}
return self;
}

OR

Option Two - TVC Lifecycle

- (void)viewDidLoad {
[super viewDidLoad];

UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
[searchBar sizeToFit];
[searchBar setDelegate:self];

[self setSearchController:[[UISearchDisplayController alloc] initWithSearchBar:searchBar
contentsController:self]];
[self.searchController setSearchResultsDataSource:self];
[self.searchController setSearchResultsDelegate:self];
[self.searchController setDelegate:self];

[self.tableView setTableHeaderView:self.searchController.searchBar]; // see Note2

...< other code as required >...
}

Note2: Regardless of which of these options you choose, you will need to place the following line of code in your viewDidLoad method...

    [self.tableView setTableHeaderView:self.searchController.searchBar]; // (or just searchBar)

Second Step:

Notes:

  • The table view that represents your complete data set (OldList) can be called using self.tableView (PS convention is to start each variable with lower case - so change your property name from OldList to oldList).

  • The table view that represents the filtered data set (filteredList) can be called using self.searchController.searchResultsTableView.

While you have prepared your tableView:cellForRowAtIndexPath: data source method, I suspect you have other data source (and maybe delegate) methods that need to be informed of which table view is the current table view, before they are able to function properly and provide you with a fully operational search results table view and search function.

For example:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (tableView == self.searchController.searchResultsTableView)
return 1;
return [[self.oldList sections] count];;
}

and:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.searchController.searchResultsTableView)
return [self.filteredList count];
return [self.oldList count];
}

Note that there may be other data source (and maybe delegate) methods that need to be informed of which table view is the current table view... I will leave it to you to determine which of these methods are to be modified, and the corresponding code necessary to adjust the table view.

Third Step:

You will be required to register a nib and reuse identifier for your search results table view.

I prefer to create a separate nib file (called "TableViewCellSearch.xib") that contains one table view cell, with the reuse identifier "SearchCell", and then place the code to register this nib and reuse identifier in the following UISearchDisplayController delegate method.

It is worth noting that this code is just as effective after the code block examples above in init/awakeFromNib/viewDidLoad.

- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
static NSString *cellIdentifierSearch = @"SearchCell";
UINib *nib = [UINib nibWithNibName:@"TableViewCellSearch" bundle:nil];
[self.searchController.searchResultsTableView registerNib:nib forCellReuseIdentifier:cellIdentifierSearch];
}

Try these suggestions.

Hope this helps.

How do I display UISearchController results in a new view and not show the background of the tableView?

What you are referring to is the presentation context of the UISearchController.

Here is a link to Apple's documentation on definesPresentationContext and the relevant piece of information we care about

this property controls which existing view controller in your view
controller hierarchy is actually covered by the new content

If you are still working off this example UISearchController from before, you are already almost done and just need to look at the following line of code inside of viewDidLoad():

self.definesPresentationContext = true

The default value for this is false. Since it's set to true, we are telling the UITableViewController that it will be covered when the view controller or one of its descendants presents a view controller. In our case, we are covering the UITableViewController with the UISearchController.

To address your question, hiding the tableView/background is as simple as clearing or switching the table's data source when the search bar is active. This is handled in the following bit of code.

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.userSearchController.active) {
return self.searchUsers.count
} else {
// return normal data source count
}
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("userCell") as! UserCell
if (self.userSearchController.active && self.searchUsers.count > indexPath.row) {
// bind data to the search data source
} else {
// bind data to the normal data source
}
return cell
}

When the search bar is dismissed, we want to reload the normal data source which is done with the following:

func searchBarCancelButtonClicked(searchBar: UISearchBar) {

// Clear any search criteria
searchBar.text = ""

// Force reload of table data from normal data source
}

Here's a link to a great article on UISearchControllers and also gives a brief overview of their inner workings and view hierarchy.

For future posts on SO, you should always try to include the relevant code samples so people are able to give the best feedback possible :)

EDIT

I think I misinterpreted your question a bit but the above is still relevant towards the answer. To display a special view when the search results are empty or nothing is typed in, do the following:

1) Add a new UIView as a child of the TableView of your UITableViewController in the storyboard with the desired labels/images. This will be next to any prototype cells you may have.

2) Create and wire up the outlets in your UITableViewController

@IBOutlet var emptyView: UIView!
@IBOutlet weak var emptyViewLabel: UILabel!

3) Hide the view initially in viewDidLoad()

self.emptyView?.hidden = true

4) Create a helper function to update the view

func updateEmptyView() {
if (self.userSearchController.active) {
self.emptyViewLabel.text = "Empty search data source text"
self.emptyView?.hidden = (self.searchUsers.count > 0)
} else {
// Keep the emptyView hidden or update it to use along with the normal data source
//self.emptyViewLabel.text = "Empty normal data source text"
//self.emptyView?.hidden = (self.normalDataSource.count > 0)
}
}

5) Call the updateEmptyView() after you've finished querying

func loadSearchUsers(searchString: String) {
var query = PFUser.query()

// Filter by search string
query.whereKey("username", containsString: searchString)

self.searchActive = true
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in

if (error == nil) {
self.searchUsers.removeAll(keepCapacity: false)
self.searchUsers += objects as! [PFUser]
self.tableView.reloadData()
self.updateEmptyView()
} else {
// Log details of the failure
println("search query error: \(error) \(error!.userInfo!)")
}
self.searchActive = false
}
}

Hope that helps!



Related Topics



Leave a reply



Submit