How to Have a Searchbar Which Shows Suggestions with Different UItableview

How can I use a searchBar in a TableView with multiple sections?

This approach is not appropriate. Instead of using a flag variable as searching and handling different scenarios, all you need to do is to define only a single array for the entire procedure. In your case your data source array would look like this:

[["uno", "dos", "tres", "cuatro"],["a", "be", "ce", "de", "e", "efe", "ge"],["alpha", "beta", "gamma"],["ichi", "ni", "san", "shi", "go", "roku", "nana", "hachi"]] 

Now, everything is much more easier to handle and implement. For example the switch case in number of rows delegate function will be replaced by:

return dataSource[section].count

What you want to do here is to map two distinct arrays to each other when a search result is tapped. I suggest you to create a class when you have multiple attributes relating to one thing:

struct Item {
var title : String // this is cell's title
var text : String // this is what will be shown on the next view controller when a cell is tapped.
}

Your data source will then look like this:

var dataSource : [[Item]] = [[Item(title: "uno" , text: """
SECTION 1, ROW 0 \n
Esto debe venir de section 1 row 0, y para hacerlo realmente largo es necesario meter un montón de cosas irrelevantes para ver si respeta los espacios y los renglones del textView. Gracias de nada.
""") , Item(title: "dos" , text: """
SECTION 1, ROW 1 \n
Esto debe venir de section 1 row 1. Una vez más es necesario asegurarse de que los márgenes y formatos de texto son respetados. De otro modo habrá que corregirlos. \n
Aquí hay un salto de línea. A ver qué tal sale.
""" ) , Item(title: "tres" , text: """
SECTION 1, ROW 2 \n
Esto debe venir de section 1 row 2. \n \n

OTRO SUBTÍTULO DENTRO DE LA SECCIÓN. \n
Se usarán 2 nuevas líneas cuando haya que añadir algún título o subtítulo dentro del textView. Por cuestiones de estética visual.
""" ), Item(title: "cuatro" , text: """
SECTION 1, ROW 3 \n
Esto debe venir de section 1 row 3
""" )] , [Item(title: "a" , text: """
SECTION 2 ROW 0 \n
Esto debe venir de section 2 row 0. Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. \n \n \n \n \n \n

Aquí sigue la onda pedorra.
""" ) , Item(title: "be" , text: "Esto debe venir de section 2 row 1" ) , Item(title: "ce" , text: "Esto debe venir de section 2 row 2" ) , Item(title: "de" , text: "Esto debe venir de section 2 row 3" ) , Item(title: "e" , text: "Esto debe venir de section 2 row 4" ) , Item(title: "efe" , text: "Esto debe venir de section 2 row 1" ) , Item(title: "ge" , text: "Esto debe venir de section 2 row 5" )]]

Now in your search delegate functions you need to remove unwanted result from the data source array based on the text or simply reset the array to defaults when cancel button is tapped. Once you've done that, all you need to do is to just reload table view:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.dataSource = values
var filteredDataSource : [[Item]] = []
for items in dataSource {
let filteredItems = items.filter { (item) -> Bool in
if item.title.lowercased().prefix(searchText.count) == searchText.lowercased() {
return true
}
return false
}
filteredDataSource.append(filteredItems)
}
self.dataSource = filteredDataSource
tableView.reloadData()

}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.dataSource = values //reseting data source to defaults
tableView.reloadData()
}

And when you select a row, you pass the section and row number incorrectly in your code. In order to pass corresponding data to the next view controller appropriately, you need to do this in your prepare for segue function:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//assuming your next view controller class's name is ViewController.
guard let detailViewController = segue.destination as? ViewController,
let row = tableView.indexPathForSelectedRow?.row,
let section = tableView.indexPathForSelectedRow?.section
else {
return
}
detailViewController.item = dataSource[section][row] //passing selected item object.
}

Finally, in your next view controller you have the item object which has both title and text properties. In your case you want to display its text property.
Hope this helps you!

EDIT

Complete solution on github.

Adding a search bar to the top of a UITableView

Usually you just use UISearchBar as a tableViewHeader for your table view. If you want it hidden when the user enters the screen (like it's done in most native apps) you can just set contentOffset for the tableView in viewWillAppear.

And I am pretty sure that's in fact how they do it. And if you think about it it's what tableHeaderView is meant for.

Try something like this:

- (void)viewDidLoad
{
[super viewDidLoad];

UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0., 0., 320., 44.)];
self.tableView.tableHeaderView = searchBar;
}

- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];

CGPoint contentOffset = self.tableView.contentOffset;
contentOffset.y += CGRectGetHeight(self.tableView.tableHeaderView.frame);
self.tableView.contentOffset = contentOffset;
}

Note that in iOS 7 you should not just set the contentOffset of your tableView to CGPointMake(0., CGRectGetHeight(self.tableView.tableHeaderView.frame)) if your viewController has automaticallyAdjustsScrollViewInsets set to YES, since it probably will not be CGPointZero in viewWillAppear:

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.

TableView search in Swift

I'm working through the same thing today and found this tutorial very easy to follow: https://github.com/codepath/ios_guides/wiki/Search-Bar-Guide

It will take you through the steps of adding the search bar in Interface Builder, setting up the delegate, and including a method to filter the results.


Providing a way for users to search through a collection of items is a fairly common task in iOS projects. A standard interface for implementing search behaviors is the search bar.

There are a few common ways to work with Search Bars:

  • Directly using a UISearchBar. This is the most bare bones way to use
    UISearchBars. This can be extremely flexible if you want to design
    and program your own search interface, however does not provide as
    many built-in features as the other methods.

  • Using a UISearchDisplayController to help manage a search interface.
    The UISearchDisplayController allows you to present a standard search
    interface with built-in animations. This method forces you to display
    search results in a table view. - DEPRECATED

  • Using a UISearchController to help manage a search interface. The

    UISearchController is a newer controller (available only in iOS 8+)

    that helps you present a search interface using any kind of view to

    display the search results.

This guide covers the very basics of working with each of these classes. None of these classes actually implements the "searching" behavior of finding items that match a given query string, since determining which objects match will vary with the domain specific use case (e.g. when searching for "people" you might want to match on just their names, whereas you may want a full-text pre-indexed search when searching through e-mails). You'll have to implement any search/filtering behavior yourself.

Working with UISearchBars directly

At its core, a search bar is nothing more than a glorified text field packaged with a scope control and some animations and a couple of buttons. Each search bar has a delegate that gives you an opportunity to respond to user actions. The most important delegate methods are:

  • textDidChange - most of the time you'll respond to this event by
    updating the displayed set of search results as the user is typing
    out a query
  • searchBarSearchButtonClicked - in some cases if the search operation
    is slow (e.g. requires making a slow API call) you'll want to wait
    until the user taps the search button before updating the search
    results.

Example searching a table

We start out with a single view application with a basic UITableView. You can add a UISearchBar as you would with any other control by dragging one to your view controller in interface builder or by programmatically adding it.

The delegate property of search bar must be set to an object that implements UISearchBarDelegate. Typically you make your view controller implement UISearchBarDelegate and set searchBar.delegate = self in viewDidLoad method.

Sample Image

The code to implement the search behavior is as follows. We maintain an additional array filteredData to represent rows of data that match our search text. When the search text changes we update filteredData and reload our table.

class ViewController: UIViewController, UITableViewDataSource, UISearchBarDelegate {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var searchBar: UISearchBar!

let data = ["New York, NY", "Los Angeles, CA", "Chicago, IL", "Houston, TX",
"Philadelphia, PA", "Phoenix, AZ", "San Diego, CA", "San Antonio, TX",
"Dallas, TX", "Detroit, MI", "San Jose, CA", "Indianapolis, IN",
"Jacksonville, FL", "San Francisco, CA", "Columbus, OH", "Austin, TX",
"Memphis, TN", "Baltimore, MD", "Charlotte, ND", "Fort Worth, TX"]

var filteredData: [String]!

override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
searchBar.delegate = self
filteredData = data
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as UITableViewCell
cell.textLabel?.text = filteredData[indexPath.row]
return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}

// This method updates filteredData based on the text in the Search Box
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// When there is no text, filteredData is the same as the original data
// When user has entered text into the search box
// Use the filter method to iterate over all items in the data array
// For each item, return true if the item should be included and false if the
// item should NOT be included
filteredData = searchText.isEmpty ? data : data.filter({(dataString: String) -> Bool in
// If dataItem matches the searchText, return true to include it
return dataString.range(of: searchText, options: .caseInsensitive) != nil
})

tableView.reloadData()
}
}

Here's what this looks like when running. Notice that the search results are displayed in the same table, and there is no presentation of a separate search interface.

source: imgur.com

Example searching a collection view

Since the UISearchBar is quite simple, it can be combined with any abitrary view to build your own search interface. Here's what it might look like paired with a collection view.

Sample Image

The code for this is essentially the same as in the case with table views.

Cancelling out of Search and hiding keyboard

Once user taps on search bar, the keyboard will appear, and you will notice that it won't go away when you tap on X. You can show Cancel button when user taps on search bar, and when user taps on Cancel, hide the keyboard.

There is a nifty searchBarTextDidBeginEditing method for UISearchBarDelegate that gets called when user starts editing search text. You can show Cancel button in that method:

func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.searchBar.showsCancelButton = true
}

When user taps on cancel button, delegate's searchBarCancelButtonClicked method gets called. At this point, you can hide the Cancel button, clear existing text in search bar and hide the keyboard like this:

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = false
searchBar.text = ""
searchBar.resignFirstResponder()
}

Using UISearchControllers (iOS 8+)

A newer way to manage the presentation of a search interface (only available in iOS 8 and above) is via the UISearchController. This controller handles some of the logic and animation of presenting a separate search interface for you while still allowing you to specify how your search results are displayed.

Example searching a table

There is currently no built-in object in the Interface Builder Object Library for a UISearchController. The easiest way to create one is to do it programatically. This also creates a UISearchBar and sets the search controller's searchBar property to it. You can add this search bar to your view hierarchy programatically.

In order to update your search results you'll have to implement the UISearchResultsUpdating protocol and set the search controller's searchResultsUpdater property.

You don't need to implement the UISearchControllerDelegate unless you need to hook into the events around the presentation of the search interface.

Putting it all together the code looks like this. Notice that we have to read the search text from the search bar in updateSearchResultsForSearchController. One other thing to note is that we set this view controller's definesPresentationContext property to true. This means that the search controller should use this view controller's frame (as oppposed to the root view controller) when presenting the search interface. In this case it means that the search interface will expand above the carrier bar.

class ViewController: UIViewController, UITableViewDataSource, UISearchResultsUpdating {
@IBOutlet weak var tableView: UITableView!

let data = ["New York, NY", "Los Angeles, CA", "Chicago, IL", "Houston, TX",
"Philadelphia, PA", "Phoenix, AZ", "San Diego, CA", "San Antonio, TX",
"Dallas, TX", "Detroit, MI", "San Jose, CA", "Indianapolis, IN",
"Jacksonville, FL", "San Francisco, CA", "Columbus, OH", "Austin, TX",
"Memphis, TN", "Baltimore, MD", "Charlotte, ND", "Fort Worth, TX"]

var filteredData: [String]!

var searchController: UISearchController!

override func viewDidLoad() {
super.viewDidLoad()

tableView.dataSource = self
filteredData = data

// Initializing with searchResultsController set to nil means that
// searchController will use this view controller to display the search results
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self

// If we are using this same view controller to present the results
// dimming it out wouldn't make sense. Should probably only set
// this to yes if using another controller to display the search results.
searchController.dimsBackgroundDuringPresentation = false

searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar

// Sets this view controller as presenting view controller for the search interface
definesPresentationContext = true
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TableCell") as UITableViewCell
cell.textLabel?.text = filteredData[indexPath.row]
return cell
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}

func updateSearchResultsForSearchController(searchController: UISearchController) {
if let searchText = searchController.searchBar.text {
filteredData = searchText.isEmpty ? data : data.filter({(dataString: String) -> Bool in
return dataString.rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
})

tableView.reloadData()
}
}
}

Here's what this looks like when running. Notice that unlike in the search display controller example, we are using the same table view to display the search results instead of overlaying of a separate table view. However, unlike when working with just the search bar, we still have the built in animation when transitioning to the search interface.

Also, you get the logic to show Cancel button and hide keyboard when user taps on cancel button for free when you use this.

Sample Image

Example searching a collection view

We can just as easily use the search controller to search a collection view in place. We still have the presentation of a search interface, but unlike when working with the search display controller we are not restricted to using a table view to display the search results.

Sample Image

The code for this is almost the same as when searching the the table view above. The only notable difference is that we had to introduce a placeholder view in interface builder for the search bar since there are still some quirks with placing a search controller's search bar inside a collection view's supplementary view.

class ViewController: UIViewController, UICollectionViewDataSource, UISearchResultsUpdating {
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var searchBarPlaceholder: UIView!
...
override func viewDidLoad() {
...
searchController.searchBar.sizeToFit()
searchBarPlaceholder.addSubview(searchController.searchBar)
automaticallyAdjustsScrollViewInsets = false
definesPresentationContext = true
}

...
}

Search Bar in Navigation View

A common requirement is to place the search bar inside the navigation bar.

Sample Image

This can be configured programatically in your view controller's viewDidLoad as follows.

When working directly with a search bar:

// create the search bar programatically since you won't be
// able to drag one onto the navigation bar
searchBar = UISearchBar()
searchBar.sizeToFit()

// the UIViewController comes with a navigationItem property
// this will automatically be initialized for you if when the
// view controller is added to a navigation controller's stack
// you just need to set the titleView to be the search bar
navigationItem.titleView = searchBar

Using a search display controller:

searchDisplayController?.displaysSearchBarInNavigationBar = true

Using a search controller:

searchController.searchBar.sizeToFit()
navigationItem.titleView = searchController.searchBar

// By default the navigation bar hides when presenting the
// search interface. Obviously we don't want this to happen if
// our search bar is inside the navigation bar.
searchController.hidesNavigationBarDuringPresentation = false

How to programmatically add a search bar to a UITableView header?

It's based on Swift 2 but It's not very diff to swift 3

Add search delegate to view controller:

UISearchResultsUpdating

Make a search:

let searchController = UISearchController(searchResultsController: nil)

Set this default values for searchController:

searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true

Add search to table:

table.tableHeaderView = searchController.searchBar

This delegate let you know start searching:

func updateSearchResultsForSearchController(searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}

Impliment your search function:

func filterContentForSearchText(searchText: String, scope: String = "All") {
// do some stuff
}

Customizing a UITableView with Searchbar

Create a separate view outside the view controller's view (or inside, it doesn't matter. you can even create this programmatically) and link it to an IBOutlet myCustomView.
Create an IBOutlet searchBar and link your UISearchBar

in viewDidLoad; you can use
[searchBar addSubView:myCustomView];
and add your custom view above the search bar.

you can show/hide (myCustomView.hidden = YES / NO) the custom view or add and remove it from superview whenever you need.

ex.

- (IBAction)didTapShowCustomHeaderButton {
myCustomView.hidden = NO;
}

- (IBAction)didTapHideCustomHeaderButton {
myCustomView.hidden = YES;
}

Implement Search bar and search display for the table view with sections

I have made the following changes and got the desired output.

I am storing my string array in the Core Data with a flag for POPUlAR FOOD in the Core Data and fetching these details and storing in different arrays according to alphabets.

Created a switch case to show the sections in the table view.

var distinctstring = [String]()
var arr = [String]()
var arrA = [String]()
var arrB = [String]()
var arrC = [String]()
var arrD = [String]()
var arrE = [String]()
var arrF = [String]()
var arrG = [String]()
var arrH = [String]()
var arrI = [String]()
var arrJ = [String]()
var arrK = [String]()
var arrL = [String]()
var arrM = [String]()
var arrN = [String]()
var arrV = [String]()
var arrX = [String]()
var arrZ = [String]()
var arrP = [String]()
var arrO = [String]()
var arrY = [String]()
var arrU = [String]()
var arrT = [String]()
var arrR = [String]()
var arrW = [String]()
var arrQ = [String]()
var arrS = [String]()

var poparr = [String]()
var filteredTableData = [String]()
var resultSearchController = UISearchController()
let collation = UILocalizedIndexedCollation.currentCollation()
as! UILocalizedIndexedCollation

override func viewDidLoad() {
super.viewDidLoad()
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
distinctstring.append("POPULAR FoodS")
var context: NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Food")
var request1 = NSFetchRequest(entityName: "Food")
if var resultsFood = context.executeFetchRequest(request, error: nil) as? [Food]
{
//println("\n Food Results in Table view : \(resultsFood)")
for resultsb in resultsFood
{

if (resultsFood.count > 0)
{
println("\(resultsb.Food_name) : \(resultsb.popularity) ")

if (resultsFood.count > 0)
{
var firstchar = resultsb.Food_name.substringToIndex(resultsb.Food_name.startIndex.successor())


Related Topics



Leave a reply



Submit