I'm currently trying to develop a custom search for an iOS app.
I have managed to get the search controller appearing and the search bar appearing properly, although my only problem is that I need the back button to appear on the right of the navigation bar rather than the left, see below
(As you can see the back button is on the left but I need it to be on the right)
http://imgur.com/qLPoIfG
Here is my code:
import UIKit
class SearchTop10Controller: UITableViewController, UISearchResultsUpdating {
override func viewDidLoad() {
super.viewDidLoad()
let searchController = UISearchController(searchResultsController: self);
self.definesPresentationContext = true;
searchController.searchResultsUpdater = self;
// searchController.hidesNavigationBarDuringPresentation = true;
searchController.dimsBackgroundDuringPresentation = false;
searchController.searchBar.sizeToFit();
self.navigationItem.titleView = searchController.searchBar;
self.tableView.tableHeaderView = searchController.searchBar;
}
override func viewDidAppear(animated: Bool) {
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
//do whatever with searchController here.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
You can add a back button to the right bar item like this:
let backButton : UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "back_icon"), style: UIBarButtonItemStyle.Plain, target: self, action: #selector(back))
self.navigationItem.rightBarButtonItem = backButton
Where back_icon is an image that you are using and back is the following function:
func back() {
self.navigationController?.popViewControllerAnimated(true)
}
To hide the left bar item:
self.navigationItem.leftBarButtonItem = nil
or:
self.navigationItem.hidesBackButton = true
Related
I've a three screens for navigate. But in one these, I can't put a UIBarButtoItem. This screen, is for create a register, and I wants create a button to "Save", that simple. When I did, I select the Bar Button Item, the XCode do not leave me drop on the bar. And programatically, also not works.
I tried this: (Not happens)
var btSalvar : UIBarButtonItem?
override func viewDidLoad() {
super.viewDidLoad()
btSalvar = UIBarButtonItem(title: "Salver", style: .plain, target: self, action: nil)
self.navigationItem.rightBarButtonItem = btSalvar
// Do any additional setup after loading the view.
}
And in storyboard: (Note: The Button "Item" not keep fixed on the bar)
You have many options to do that, One of them is:
You have to create a super view controller and add navigation button code in it. I have added a back button for a demo:
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
/**
To add the left back button on navigation.
*/
var addLeftBarMenuButtonEnabled: Bool? {
didSet {
if addLeftBarMenuButtonEnabled! {
let leftBarBtn = UIButton()
leftBarBtn.setImage(UIImage(named: "backIcon"), for: .normal)
leftBarBtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
leftBarBtn.addTarget(self, action: #selector(actionBackButton), for: .touchUpInside)
self.navigationItem.leftBarButtonItem = UIBarButtonItem.init(customView: leftBarBtn)
} else {
self.navigationItem.setHidesBackButton(true, animated: true)
}
}
}
///This is action method for back button
#objc func actionBackButton() {
self.view.endEditing(true)
self.navigationController?.popViewController(animated: true)
}
}
Now you need to use the back button in your view controller which super view controller is MainViewController:
class ViewController: MainViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.addLeftBarMenuButtonEnabled = true
}
}
You can add navigation button like that and use where you want. If you want to use it in every view controller then you have to add 'self.addLeftBarMenuButtonEnabled = true' in main view controller like that
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.addLeftBarMenuButtonEnabled = true
}
}
I'm trying to use the standard UIRefreshControl and UISearchController on a UITableViewController. However it doesn't look like it does what it's supposed to. When refreshing, scrolling leaves the navigation bar with a big blank area, presumably where the spinner is supposed to be:
I have a sample project on GitHub. Here's how the controls are set up:
override func viewDidLoad() {
super.viewDidLoad()
let spinner = UIRefreshControl()
spinner.addTarget(self, action: #selector(refresh), for: .valueChanged)
refreshControl = spinner
searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
}
I've tried assigning the refresh control to the property on UITableView instead of the one on UITableViewController, that doesn't make a difference.
Has anyone come across the same issue?
You can use UIRefreshController in the old way, which is like this:
override func viewDidLoad() {
super.viewDidLoad()
let spinner = UIRefreshControl()
spinner.addTarget(self, action: #selector(refresh), for: .valueChanged)
self.tableView.addSubview(spinner)
searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
}
Just recreate and assign the refresh control every time the table view controller appears on screen.
If you subclassed UITableViewController:
class MyTableViewController: UITableViewController {
...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
refreshControl = UIRefreshControl(...)
}
}
If you use view controller containment:
class MyContainerViewController: UITableViewController {
private let tableViewController = UITableViewController(style: .plain)
...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableViewController.refreshControl = UIRefreshControl(...)
}
}
I have implemented a search controller in a viewController with a table view and also a search controller, the search bar is displayed when search button is taped, search button is a UIBarButtonItem and the searchBar is shown in the navigation controller but I want to make disappear when tap on cancel button, I have tried using serarchBarDelegate protocol but nothing happens on tap here the code
class NewsTVController: UIViewController, UITableViewDataSource, UITableViewDelegate,UISearchResultsUpdating,UISearchBarDelegate{
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
definesPresentationContext = true
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = true
self.searchController.hidesNavigationBarDuringPresentation = false
loadNews()
}
#IBAction func searchButtonTaped(sender:UIBarButtonItem){
print("tap inside")
self.navigationItem.titleView = searchController.searchBar
//self.navigationItem.rightBarButtonItem?.action = #selector(hideSearchBar(:))
// searchController.searchBar.touchesCancelled(UITouch, with: .touchUpInside){
//}
//self.navigationItem.rightBarButtonItem.
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
hideSearchBar()
}
func hideSearchBar() {
print("hay que escpder")
//navigationItem.setLeftBarButtonItem(searchBarButtonItem, animated: true)
//logoImageView.alpha = 0
UIView.animate(withDuration: 0.3, animations: {
self.navigationItem.titleView = nil// = self.logoImageView
self.navigationItem.title = "Eventos"
//self.logoImageView.alpha = 1
}, completion: { finished in
})
}
}
here the pic of the navigation controller with a search button and the search bar
what I want is that when the cancel button is tapped the navigation bar stay as in first pic, no search bar.
and some tips there is a way to hide the back button and the search button when search bar appears.
as i don´t find a way to achive this i found this solution
#IBAction func searchButtonTaped(sender:UIBarButtonItem){
print("tap inside")
self.navigationItem.titleView = searchController.searchBar
searchController.searchBar.setShowsCancelButton(false, animated: false)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Cancelar", style: .plain, target: self, action: #selector(hideSearchBar(sender:)))
//self.searchIcon.is
//self.navigationItem.rightBarButtonItem?.action = #selector(hideSearchBar(:))
// searchController.searchBar.touchesCancelled(UITouch, with: .touchUpInside){
//}
//self.navigationItem.rightBarButtonItem.
}
func hideSearchBar(sender:UIBarButtonItem) {
print("hay que escpder")
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.search, target: self, action: #selector(searchButtonTaped(sender:)))
//logoImageView.alpha = 0
UIView.animate(withDuration: 0.3, animations: {
self.navigationItem.titleView = nil// = self.logoImageView
self.navigationItem.title = "Noticias"
//self.logoImageView.alpha = 1
}, completion: { finished in
})
}
and boila the search bar now dissapear from navigation controller nad the search button is functional since is linked to searchButtonTaped in Interface Builder
I have a NavigationBar at the top of a TableView. It looks nice opening/closing the search.
However, if I click on a button in a cell and get directed to another page (with segue); and then use Back button to unwind, it seems like bugged.
()
So it looks like it is pressed and opened but it shouldn't have. It should be looked like the top picture instead (just UIBarButtonItem - search button)
I couldn't figure out the issue creating this problem.
Please note that < Back is created automatically and I didn't write any code to create it. Is there something I am doing wrong?
Update: Added some snippets...
First, created a different class for handling the search
class SearchBarViewController: UIViewController, UISearchBarDelegate {
var searchBar : UISearchBar?
var searchBarWrapper : UIView?
var searchBarButtonItem : UIBarButtonItem?
func constructSearchBar()
{
searchBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: "showSearchBar")
self.navigationItem.rightBarButtonItem = searchBarButtonItem
}
func showSearchBar() {
// styling & configuration
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
UIView.animateWithDuration(0.2, animations: {
self.searchBar?.resignFirstResponder()
self.searchBarWrapper?.alpha = 0
}, completion: { (success) -> Void in
self.searchBar = nil
self.searchBarWrapper = nil
self.navigationItem.rightBarButtonItem = self.searchBarButtonItem
})
}
}
And my ViewController:
class ViewController: SearchBarViewController {
override func viewDidLoad() {
super.viewDidLoad()
constructSearchBar()
}
}
Regarding to emrys57's answer, I tried adding viewWillAppear() in my ViewController but I couldn't make it work, as my cancel looks a little different:
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
// Here, I couldn't figure out what to put because
// my searchBarCancelButtonClicked() needs searchBar and
// forces me to use (!) but then it says, it's optional..
}
The answer is...
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
navigationItem.titleView = nil
constructSearchBar()
}
You have not posted code, so it's not entirely clear what's gone wrong. Using UISearchBar, I think you must be handling the buttons separately yourself, as opposed to using UISearchController. I think that you may not be clearing away the search bar when coming back from the second VC. This code clears out the search bar in viewWillAppear:
class ViewController: UIViewController {
var cancelButton: UIBarButtonItem?
var searchButton: UIBarButtonItem?
override func viewDidLoad() {
super.viewDidLoad()
cancelButton = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: Selector("searchCancelPressed:"))
searchButton = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: Selector("searchPressed:"))
}
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
searchCancelPressed(nil)
}
func searchPressed(sender: AnyObject) {
navigationItem.titleView = UISearchBar()
navigationItem.rightBarButtonItem = cancelButton
}
func searchCancelPressed(sender: AnyObject?) {
navigationItem.titleView = nil
navigationItem.rightBarButtonItem = searchButton
}
}
and that is working nicely for me when I do a push from a button to the second VC and then hit back.
Following the edit to the original question, this code seems to work, although it may not be the most elegant way of constructing the answer:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationItem.titleView = nil
searchBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: "showSearchBar")
navigationItem.rightBarButtonItem = searchBarButtonItem
}
The function constructSearchBar no longer needs to be called in viewDidLoad, and can be deleted.
I have 3 pages
Page 1: Menu
Page 2: Menu > Navigation Controller > Map listview
Page 3: Menu > Navigation Controller > Map
It's possible to switch between page 2 and 3 but when you click "Back" it always goes to page 1 and I did this using a custom back button.
After having used the custom back button once the following problem appears:
When I go to page 2 or 3 from the Menu page (Page 1) the navigation title appears and in less than a second it disappears. How is this possible?
These are the functions I am using:
private func hideAndAddNewBackButton(){
if backToRoot{
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = newBackButton;
self.title = "Locaties"
}
}
func back(sender: UIBarButtonItem) {
if let viewController2 = storyboard!.instantiateViewControllerWithIdentifier("ViewController2") as? ViewController2{
self.navigationController?.pushViewController(viewController2, animated: true);
}
}
func needBackToRoot(){
backToRoot = true;
}
And this is in my viewDidLoad():
var backToRoot:Bool = false;
override func viewDidLoad() {
super.viewDidLoad()
self.hideAndAddNewBackButton();
}
My switch button:
#IBAction func showLijst(sender: AnyObject) {
if let viewController3 = storyboard!.instantiateViewControllerWithIdentifier("Lijst") as? KaartListview{
viewController3.needBackToRoot();
self.navigationController?.pushViewController(viewController3, animated: true);
}
}
In my case problem was creating custom back button and setting in pushed controller
self.navigationController?.navigationBar.topItem?.title = ""
My solutions is :
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.isNavigationBarHidden = false
self.navigationController?.navigationBar.topItem?.title = "SomeTitle"
}
I had a similar issue before and I fixed by using:
navigationController?.navigationBarHidden = false
In the viewDidLoad() function
Like this:
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBarHidden = false
}