Showing posts with label uisearchbar. Show all posts
Showing posts with label uisearchbar. Show all posts

Tuesday, October 16, 2018

Hide Navigation Controller Search Bar & opened Large Title programmatically

Leave a Comment

I have a tableView. I set the all settings about searchController ( Search Bar in Large Navigation Bar ) - ( open / close when scroll tableview ). I implemented rightBarButtonItem which name is 'Close' . I want to hide/close tableView and Search Bar with programmatically. I can hide tableView but not SearchBar.

When I do isHidden for SearchBar , The Large Navigation Bar doesnt shrink to normal size.

Pic 1. Opened search bar with scroll down.

enter image description here

Pic 2. Not Hidden Large Navigation Bar with programmatically ( searchar.isHidden not implemented here )

enter image description here

Thanks in advance.

I tried this before but not run

tableView.setContentOffset(.zero, animated: false) navigationController?.navigationBar.prefersLargeTitles = false 

2 Answers

Answers 1

I tried to find a proper way to hide search bar, but I didn't find. But I found a workaround to hide your search bar which is change content offset your table view.

You may try this function to hide your table view and search bar.

func hide() {     tableView.isHidden = true     let point = tableView.contentOffset     let searchBarFrame = self.navigationItem.searchController?.searchBar.frame     let newPoint = CGPoint(x: point.x, y: point.y + searchBarFrame!.height)     tableView.setContentOffset(newPoint, animated: true) } 

Answers 2

Just try this:

 navigationItem.searchController = nil 

This is all my test code:

@IBOutlet weak var tableView: UITableView!  @IBOutlet weak var leftBarButtonItem: UIBarButtonItem!  var isHidden = false  var searchController: UISearchController {      let search = UISearchController(searchResultsController: nil)      search.searchBar.placeholder = "hello world"      search.obscuresBackgroundDuringPresentation = false      return search }   override func viewDidLoad() {     super.viewDidLoad()      self.navigationItem.title = "Test"      tableView.delegate = self      tableView.dataSource = self      showSearchController() }  @IBAction func isHiddenAction(_ sender: UIBarButtonItem) {     isHidden = !isHidden      self.tableView.isHidden = isHidden      if isHidden {         leftBarButtonItem.title = "Show"         hiddenSearchController()      } else {         leftBarButtonItem.title = "Hidden"         showSearchController()     } }  func hiddenSearchController() {     navigationItem.searchController = nil }  func showSearchController() {      navigationItem.searchController = searchController      navigationItem.hidesSearchBarWhenScrolling = true      definesPresentationContext = true } 

screenShots

Read More

Thursday, February 1, 2018

iOS - ScopeBar overlaps SearchBar in UISearchController in TabBarController

Leave a Comment

I am running into a peculiar issue regarding a scope bar shown under my UISearchBar. Basically, the issue I previously had was that whenever my UISearchController was active and the user switched tabs, if he came back to the UIViewController containing the UISearchController, the background would turn back. This issue was solved by embedding the UIViewController into a UINavigationController.

Now, a new issue has appeared. When I switch tabs with the UISearchController already active, when I switch back, the UIScopeBar is displayed on top of the UISearchBar. This can only be fixed by Canceling the search, and starting over.

Illustration: enter image description here

I have tried hiding the following code:

-(void)viewWillAppear:(BOOL)animated{ if(self.searchController.isActive){     [self.searchController.searchBar setShowsScopeBar:TRUE]; } }  -(void)viewDidDisappear:(BOOL)animated{     if(self.searchController.isActive){         [self.searchController.searchBar setShowsScopeBar:FALSE];     } } 

To no avail. If anybody has a trick for this one, I'd be glad to try it out.

1 Answers

Answers 1

Setting a constraint programatically each time you generate the view and come back to that tab might do the trick by keeping the UIScopeBar at a fixed distance from the top. You can also try setting the contraint between UIScopeBar and UISearchBar.

NSLayoutConstraint *topSpaceConstraint = [NSLayoutConstraint constraintWithItem:self.view                                                                              attribute:NSLayoutAttributeTop                                                                              relatedBy:NSLayoutRelationEqual                                                                                 toItem:UIScopeBar                                                                               attribute:NSLayoutAttributeTop                                                                             multiplier:1.0                                                                               constant:5.0]; [self.view addConstraint:topSpaceConstraint]; 

If this does not do the trick, you'll need to provide more code for me/people here to replicate the bug you're having.

Read More

Sunday, October 1, 2017

How to lock UISearchBar in place to superview

Leave a Comment

I am using the UISearchController alongside its UISearchBar. The UISearchController alongside its UITableView is placed inside a subview in my main view.

My goal is to lock the UISearchBar in its place so when its active, it does not move. Right now the following is happening:

enter image description here enter image description here

I have searched this issue extensively and have tried the following such as:

  1. self.searchController.hidesNavigationBarDuringPresentation = false, which just abruptly moves the search bar to the middle of the screen.

  2. definesPresentationContext = true, which does not change behavior

  3. self.extendedLayoutIncludesOpaqueBars = true, which does not change behavior

  4. Using the UIBarPositioningDelegate method mentioned here, which strangely cannot be translated to Swift because I cannot insert the AnyObject<UIBarPositioning> as it is in the Objective C version and still have it recognized as the override function

Any suggestion is appreciated.

Edit:

Here is the setup for the search items:

    searchController.searchResultsUpdater = self     searchController.dimsBackgroundDuringPresentation = false     definesPresentationContext = true     searchTableView.tableHeaderView = searchController.searchBar 

1 Answers

Answers 1

Set your TableView's Style property to Plain in the Storyboard and use the SearchBar as the section header view. Along with the following code, I commented out tableView.tableHeaderView = searchController.searchBar in Apple's "Table Search with UISearchController" example and it worked fine.

override func numberOfSections(in tableView: UITableView) -> Int {     return 1 } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {     return searchController.searchBar.frame.size.height } override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {     return searchController.searchBar } 
Read More

Tuesday, August 1, 2017

searchBar overlapped by section header view

Leave a Comment

I put the searchBar inside the tableHeaderView. Everything works fine on iphone 6 but on iphone 5s I get this weird result?

 override func viewDidLoad() {     super.viewDidLoad()     tableView.delegate = self     tableView.dataSource = self     tableView.sectionIndexColor = Constants.Colors.ThemeGreen     tableView.sectionIndexBackgroundColor = UIColor.clearColor()     tableView.sectionIndexTrackingBackgroundColor = UIColor.clearColor()     tableView.contentInset = UIEdgeInsetsMake(0, 0, CGFloat(Constants.Dimensions.TabBarHeight), 0)     resultSearchController = UISearchController(searchResultsController: nil)     resultSearchController.searchResultsUpdater = self     resultSearchController.dimsBackgroundDuringPresentation = false     resultSearchController.definesPresentationContext = true     tableView.tableHeaderView = resultSearchController.searchBar     resultSearchController.searchBar.sizeToFit()   //Fetch data for the first time     do{       try fetchedResultsController.performFetch()       listHeaderView?.count = "\(fetchedResultsController.fetchedObjects!.count)"     }catch{       print("Error - Couldn't fetch list")     } 
  • NOTE: I'm using a NSFetchedResultController to retrieve the data

enter image description here

4 Answers

Answers 1

Here is the solution. Don't call sizeToFit() AFTER putting the searchBar in tableHeaderView but call it BEFORE. What the hell is going on behind the scene... I wonder..

resultSearchController.searchBar.sizeToFit() //Important to call sizeToFit BEFORE adding it to tableHeaderView or you get layout issues tableView.tableHeaderView = resultSearchController.searchBar 

Answers 2

It seems only below line of code does work ... nothing else seems to work right now.

self.tableView.beginUpdates()        // self.tableView.setTableHeaderView(headerView: self.filterView!)         //self.tableView.reloadData()         self.tableView.layoutIfNeeded()         self.tableView.layoutSubviews()         self.tableView.endUpdates() 

everytime your table resize or change constraints you need to call above code.

Answers 3

@mihir mehta

You can also try the same as

searchControl.searchBar.clipToBounds = true 

I think it works for your code.

Answers 4

Try this it may work

resultSearchController.clipToBounds = true

You can also try the same as

searchControl.searchBar.clipToBounds = true 

I think it works for your code.

Read More

Friday, March 11, 2016

Adding Scope Bar in swift

Leave a Comment

The app shows a list of cars parts (car part, type, year, country) it is working in a tableview with a search bar.

Now I decided to add a scope bar to filter the results, and I am sure I messed up with the code. There are many errors in the lines to add the scopeBar. It is the last 20 lines, after the comment //ScopeBar try, other than this last lines I added a code in the viewDidLoad() to show the titles I want.

What am I doing wrong? Any help is more than welcome, I am trying to fix this for 2 days already no luck.

import UIKit import CoreData  class DictionaryTableViewController: UITableViewController, NSFetchedResultsControllerDelegate, UISearchResultsUpdating {      var searchController:UISearchController!     var searchResults:[Dictionary] = []      private var dictionaryItems:[Dictionary] = []      private var cockpitDict = [String: [Dictionary]]()     var sectionTitles = [String]()      var fetchResultController:NSFetchedResultsController!      override func viewDidLoad() {         super.viewDidLoad()           // ScopeBar Try         searchController.searchBar.scopeButtonTitles = ["All", "type", "year", "country"]         tableView.tableHeaderView = searchController.searchBar            // Load menu items from database         if let managedObjectContext = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext {              let fetchRequest = NSFetchRequest(entityName: "DictionaryEntity")             do {                 dictionaryItems = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Dictionary]             } catch {                 print("Failed to retrieve record")                 print(error)             }         }          searchController = UISearchController(searchResultsController: nil)         tableView.tableHeaderView = searchController.searchBar         searchController.searchResultsUpdater = self         searchController.dimsBackgroundDuringPresentation = false         searchController.searchBar.placeholder = "Search ..."          navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style:             .Plain, target: nil, action: nil)          // Enable self sizing cells         tableView.estimatedRowHeight = 100.0         tableView.rowHeight = UITableViewAutomaticDimension           createCockpitDict()     }      override func didReceiveMemoryWarning() {         super.didReceiveMemoryWarning()         // Dispose of any resources that can be recreated.     }      func createCockpitDict(){          for item in dictionaryItems {              guard let word = item.word else {                 break             }              // Get the first letter of the word and build the dictionary             let wordKey = word.substringToIndex(word.startIndex.advancedBy(1))             if var cockpitItems = cockpitDict[wordKey] {                 cockpitItems.append(item)                 cockpitDict[wordKey] = cockpitItems             } else {                 cockpitDict[wordKey] = [item]             }         }          // Get the section titles from the dictionary's keys and sort them in ascending order         sectionTitles = [String](cockpitDict.keys)         sectionTitles = sectionTitles.sort({ $0 < $1 })     }  //    create a standard way to get a Dictionary from a index path     func itemForIndexPath (indexPath: NSIndexPath) -> Dictionary? {         var result: Dictionary? = nil          if searchController.active {             result = searchResults[indexPath.row]         }else{             let wordKey = sectionTitles[indexPath.section]             if let items = cockpitDict[wordKey]{                 result = items[indexPath.row]             }         }         return result     }      // MARK: - Table view data source      override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {         return sectionTitles[section]     }      override func numberOfSectionsInTableView(tableView: UITableView) -> Int {         //assume a single section after a search         return (searchController.active) ? 1 : sectionTitles.count     }      override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {          if searchController.active {             return searchResults.count         } else {             // Return the number of rows in the section.             let wordKey = sectionTitles[section]             if let items = cockpitDict[wordKey] {                 return items.count             }              return 0         }     }       override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {          let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DictionaryTableViewCell          //let dictionary = (searchController.active) ? searchResults[indexPath.row]: dictionaryItems[indexPath.row]         if let dictionary = itemForIndexPath(indexPath){             cell.wordLabel.text = dictionary.word             cell.definitionSmallLabel.text =  dictionary.definition             cell.typeLabel.text = dictionary.type             cell.yearLabel.text = dictionary.year             cell.countryLabel.text = dictionary.country           }else{             print("Cell error with path\(indexPath)")         }             return cell     }      override func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {         return sectionTitles     }      // Override to support conditional editing of the table view.     override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {         // Return false if you do not want the specified item to be editable.         if searchController.active{             return false         }else{             return true         }     }       override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {         if segue.identifier == "showDictionaryDetail" {             if let indexPath = tableView.indexPathForSelectedRow {                 let destinationController = segue.destinationViewController as! DictionaryDetailViewController                 if let dictionary = itemForIndexPath(indexPath){                     destinationController.dictionary = dictionary                 }else{                     print("Segue error with path \(indexPath)")                 }                 searchController.active = false             }         }     }      func updateSearchResultsForSearchController(searchController: UISearchController) {             if let searchText = searchController.searchBar.text {                 filterContentForSearchText(searchText)                 tableView.reloadData()             }     }      func filterContentForSearchText(searchText: String) {         searchResults = dictionaryItems.filter({ (dictionary:Dictionary) -> Bool in             let wordMatch = dictionary.word!.rangeOfString(searchText, options:                 NSStringCompareOptions.CaseInsensitiveSearch)             return wordMatch != nil         })     }     }  //ScopeBar try: all lines below got many errors I can not figure out how to fix it :(  func filterContentForSearchText(searchText: String, scope: String = "All") {     dictionaryItems = cockpitDict.filter({( cockpitDict : Dictionary) -> Bool in         let categoryMatch = (scope == "All") || (cockpitDict.category == scope)         return categoryMatch && cockpitDict.name.lowercaseString.containsString(searchText.lowercaseString)     })     tableView.reloadData() }  extension DictionaryTableViewController:UISearchBarDelegate {     // MARK: - UISearchBar Delegate     func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {         filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])     } }  extension DictionaryTableViewController: UISearchResultsUpdating {     // MARK: - UISearchResultsUpdating Delegate     func updateSearchResultsForSearchController(searchController: UISearchController) {         let searchBar = searchController.searchBar         let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]         filterContentForSearchText(searchController.searchBar.text!, scope: scope)     } } 

2 Answers

Answers 1

There are a few issues with this code. For starters, as others have pointed out, var searchResults:[Dictionary] = [] isn't valid syntax. A Dictionary in Swift requires a type specification, such as Dictionary<String: AnyObject>. I'm guessing based off the rest of your code that you've named a custom entity named Dictionary, which may be causing the confusion.

The next issue I see is that on lines 8 and 10, you need to initialize the array, using (), i.e. var searchResults:[Dictionary] = [](). (Again, this is assuming you fix the issue of declaring your Dictionary type correctly.)

Another issue is your filter statement on line 192:

dictionaryItems = cockpitDict.filter({( cockpitDict : Dictionary) -> Bool in     let categoryMatch = (scope == "All") || (cockpitDict.category == scope)     return categoryMatch && cockpitDict.name.lowercaseString.containsString(searchText.lowercaseString) }) 

Let's take a look at the definition of cockpitDict on line 12:

private var cockpitDict = [String: [Dictionary]]() 

Because this is an Array with a String key and an Array<Dictionary> value, you have both a key and value to capture in the closure. The filter statement needs to be different, something like this (again, I've made some assumptions on the definition of your custom Dictionary type):

dictionaryItems = cockpitDict.filter({(key, value) -> Bool in     let categoryMatch = (scope == "All") || (value.category == scope)     return categoryMatch && value.name.lowercaseString.containsString(searchText.lowercaseString) }) 

Answers 2

I went through whole code provided in github and resolved it

Change your viewDidLoad to

 override func viewDidLoad() {         super.viewDidLoad()          // Load menu items from database         if let managedObjectContext = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext {              let fetchRequest = NSFetchRequest(entityName: "DictionaryEntity")             do {                 dictionaryItems = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Dictionary]             } catch {                 print("Failed to retrieve record")                 print(error)             }         }          searchController = UISearchController(searchResultsController: nil)         tableView.tableHeaderView = searchController.searchBar         searchController.searchResultsUpdater = self         searchController.dimsBackgroundDuringPresentation = false         searchController.searchBar.placeholder = "Search ..."  // you were setting before initialization         searchController.searchBar.scopeButtonTitles = ["All", "type", "year", "country"]          navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style:             .Plain, target: nil, action: nil)          // Enable self sizing cells         tableView.estimatedRowHeight = 100.0         tableView.rowHeight = UITableViewAutomaticDimension           createCockpitDict()     } 

and For last scopebar filtering

func filterContentForSearchText(var searchText: String, scope: NSInteger) {   searchText = searchText.lowercaseString;  func checkString(strData: String, strSearchData: String)-> Bool{    return strData.rangeOfString(strSearchData, options:         NSStringCompareOptions.CaseInsensitiveSearch) != nil }  searchResults = dictionaryItems.filter({ (dictionary:Dictionary) -> Bool in      switch scope {     case 0:         return (checkString(dictionary.word!, strSearchData: searchText) || checkString(dictionary.type!, strSearchData: searchText) || checkString(dictionary.country!, strSearchData: searchText) || checkString(dictionary.year!, strSearchData: searchText))     case 1:         return checkString(dictionary.type!, strSearchData: searchText)     case 2:         return checkString(dictionary.year!, strSearchData: searchText)     case 3:         return checkString(dictionary.country!, strSearchData: searchText)     default:         return true;     }  })  tableView.reloadData()  }   // MARK: - UISearchBar Delegate func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {         filterContentForSearchText(searchBar.text!, scope: searchBar.selectedScopeButtonIndex) }    // MARK: - UISearchResultsUpdating Delegate - comment older method so duplicate method error will be vanished func updateSearchResultsForSearchController(searchController: UISearchController) {     let searchBar = searchController.searchBar     filterContentForSearchText(searchController.searchBar.text!, scope: searchBar.selectedScopeButtonIndex) } 
Read More