Remove back button when using custom uinavigationbar with uinavigationcontroller - swift

I'm having trouble finding a way to remove a 'ghost' back button (nothing but a blue back arrow) when I initialize my uinavigationcontroller with a custom uinavigationbar. When I click that back button, I then see my custom navigationbar, but I would like to not have to click that back button.
I've tried almost all other solutions, including setHidesBackButton, etc. and playing with the order in which I call these functions.
class TabsVC : UITabBarController {
func setupTabBar() {
// setup feed tab
let navVC = UINavigationController(navigationBarClass: NavBar.self, toolbarClass: nil)
self.navigationItem.setHidesBackButton(true, animated: false)
let feedVC = FeedVC()
navVC.pushViewController(feedVC, animated: false)
let feedIcon = UIImage.fontAwesomeIcon(name: .home, textColor: ColorConstants.baseColor, size: CGSize(width: 40, height: 40))
navVC.tabBarItem = UITabBarItem(title: "", image: feedIcon, tag: 1)
// other tabs stuff
}
class NavBar : UINavigationBar {
func prepare() {
let item = UINavigationItem(title: "")
let titleV = titleView()
item.titleView = titleV
item.hidesBackButton = true
item.setHidesBackButton(false, animated: false)
item.leftBarButtonItem = UIBarButtonItem(image: UIImage.fontAwesomeIcon(name: .userCircle, textColor: ColorConstants.baseColor, size: CGSize(width: 40, height: 40)), style: .plain, target: nil, action: nil)
item.leftBarButtonItem?.tintColor = .white
item.leftBarButtonItem?.action = #selector(moveToProfileScreen)
self.pushItem(item, animated: false)
}
I just want to be able to see my custom nav bar from the beginning, and not have to click an empty back button to see the nav bar. Thanks!

Related

Swift - Popover controller shows up on wrong corner depending on load time

I recently started having an issue where the popover controller will some times show up on the wrong corner. When it works correctly, the popover source is a button on the upper right corner. This is what happens most o the time. Now, when I land on this page "too quickly" from a specific route, the popover shows up on the upper left corner.
Another thing that is weird is that when loading is artificially delayed (like when I set break points for debugging) the popover shows up correctly.
Since it seemed to be a timing issue, I tried moving the navigation configuration from viewDidLoad to viewDidAppear, but this didn't work.
This function is called from viewDidLoad:
func configureNav() {
if canAddDoc == true {
let customButton = UIButton(type: .system)
customButton.setImage(with: .add, tintColor: UIColor.white, imageEdgeInsets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
customButton.addTarget(self, action: #selector(showAddDocSheet), for: .touchUpInside)
addButton = UIBarButtonItem(customView: customButton)
}
shareButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.action,
target: self,
action: #selector(shareButtonPressed))
navigationItem.rightBarButtonItems = (addButton == nil) ? [shareButton!] : [shareButton!, addButton!]
#objc func showAddDocSheet() {
guard let addButton = addButton else { return }
self.displayActionSheet(sourceButton: addButton)
}
}
func displayActionSheet(sourceButton: UIBarButtonItem) {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
//Action sheet code goes here
if let popoverController = actionSheet.popoverPresentationController {
popoverController.barButtonItem = sourceButton
popoverController.sourceView = sourceButton.customView
popoverController.permittedArrowDirections = .up
}
self.present(actionSheet, animated: true, completion: nil)
}
This may sound a weird solution but something similar happened to me before and it got solved when setting the animation to false while presenting the VC ,
self.present(actionSheet, animated: false, completion: nil)

Possible to create a UITableView that appears from the corner of a View Controller

I would like to model a table view after one found in the Todoist app (see below), is it possible to do this without and additional framework? If so how would I go about doing this?
You can create a view controller with a UITableView and present it as UIPopoverPresentationController
let vc = UIViewController()
vc.modalPresentationStyle = .popover
vc.preferredContentSize = CGSize(width: 200, height: 200)
let popUp = vc.popoverPresentationController
popUp?.permittedArrowDirections = .up
popUp?.delegate = self
popUp?.sourceView = sender as! UIView // here set the frame of the button that the arrow points to when popup is shown
present(vc, animated: true, completion: nil)
//
Inside the vc that you presents the popup make it implements the delegate UIPopoverPresentationControllerDelegate and write this method
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}

How to Change back button title on navigation controller in swift3?

I want to change the title of backbutton to any name in swift 3.I tried many ways but none of them worked for me.
self.navigationItem.backBarButtonItem?.title="Title"
self.navigationController?.navigationItem.backBarButtonItem?.title="Title"
Just for information i have written below code in appdelegate.
let backImage : UIImage = UIImage(named:"backArrow")!
UINavigationBar.appearance().barTintColor = UIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0)
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white]
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, 0), for: .default)
IQKeyboardManager.sharedManager().enable = true
self.window?.backgroundColor = UIColor.white
Navigation item back button name will be same as the title of previous view controller which is pushing it to the navigation stack :)
So if VC A pushes VC B, back button in VC B will be A.
So all you can do is, to change the title of the previous viewController before pushing the new viewController using code :)
self.navigationItem.title = "ABCD"
And in ViewWillAppear of VC A,you can revert the title back to whatever it was earlier :)
self.navigationItem.title = "Back to xyz"
All that being said, if you don't want all this circus :) you can simply hide the default back button using,
self.navigationItem.hidesBackButton = true
in your VC B, create a UIBarButton item, set whatever the title you want to set and then set that as leftBarButtonItem :) using,
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("ABCD", comment: "ABCD"), style: .plain, target: self, action:#selector(self.abcdTapped:)
of course now that will not show "<" icon :) Now if you want that as well you can add it as a image to back bar button item :) but its cumbersome :)
Hope it helps :)
You will have to set the backBarButtonItem property of the navigationItem of the viewController that you push the said viewController from.
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: nil, action: nil)
However, you must set this for each viewController.
This is the way:
extension UINavigationController {
func addCustomBackButton(title: String = "Back") {
let backButton = UIBarButtonItem()
backButton.title = title
navigationBar.topItem?.backBarButtonItem = backButton
}
}
In Swift 3.0 put below code in appdelegate didFinishLaunchingWithOptions method its worked perfectly for me
let backImage = UIImage(named: "BackNavigation")?.withRenderingMode(.alwaysOriginal)
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -80.0), for: .default)
The last line will remove the title of Navigation Back Button if you don't want to remove title then just comment it
I didn't find the answer that I was looking for so I share with you my solution.
Sometimes you have to change the text of the back button in the parent ViewController and not in the ViewController where seems to be defined the back button, remember that a navigation controller stacks ViewControllers one after another.
In my case I did this on the function prepare(for segue: ) of the "ParentViewController":
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showChildViewController" {
if let childViewController = segue.destination as? ChildViewController {
let backItem = UIBarButtonItem()
backItem.title = "Back"
navigationItem.backBarButtonItem = backItem
}
}
Try following steps to set image to your back button..
Output:
Step 1:
Add following code to your AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
var backButtonImage = UIImage(named: "Your Image Name")
backButtonImage = backButtonImage?.stretchableImage(withLeftCapWidth: 0, topCapHeight: 0)
UIBarButtonItem.appearance().setBackButtonBackgroundImage(backButtonImage, for: .normal, barMetrics: .default)
UINavigationBar.appearance().barTintColor = UIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0)
UINavigationBar.appearance().tintColor = UIColor.white
return true
}
Step 2:
Add following code to your MainVC
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "Title 1"
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white, NSFontAttributeName:UIFont(name:"HelveticaNeue", size: 20)!]
}
Step 3:
Add following code to your DestVC or 2ndVC
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "Title 2"
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white, NSFontAttributeName:UIFont(name:"HelveticaNeue", size: 20)!]
}
Step 4:
Select your navigationBar from your StoryBoard and goto Attribute Inspector. Under Navigation Item change your Back Button name enter a empty space or programatically create a back button with plain title..
Step 5:
Add icon image to your Assets. 1x29pt,2x58pt and 3x87pt. I am not sure about the asset image size.Check with apple doc about the size class..
Update:
My Similar answer related to this post.
How to customize the navigation back symbol and navigation back text?
You can easily do that from the storyboard by setting the title of the previous screen. Image explaining how to do that from storyboard - or you can do that by adding the following code to the view controller you're navigating BACK to.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
let backItem = UIBarButtonItem()
backItem.title = "Title"
navigationItem.backBarButtonItem = backItem
}
in viewDidLoad()
let backBarButtonItem = UIBarButtonItem(title: "You back button title here", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backBarButtonItem

UIBarButtonItems created programatically with Swift, not visible

I'm not sure why this piece of code which is supposed to embed two bar button items in a navigation controller's toolbar won't work. The toolbar itself is visible when I run my code, but not the bar button items. What am I doing wrong here? Thanks for attention.
class NavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
//Tool bar appearance
toolbar.barTintColor = UIColor.blackColor()
//Show tool bar by default
self.navigationController?.toolbarHidden = false
//Icons all located in images.xcassets
let homeImage = UIImage(named: "home")
let gameImage = UIImage(named: "logo")
var toolBarItems = [UIBarButtonItem]()
let homeButton = UIBarButtonItem(image: homeImage, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(NavigationController.toHome))
homeButton.title = "Home"
let gameButton = UIBarButtonItem(image: gameImage, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(NavigationController.toGame))
homeButton.title = "Game"
//Place the bar items in toolBarItems array
toolBarItems.append(homeButton)
toolBarItems.append(gameButton)
//self.toolbar.items = toolBarItems
self.toolbar.setItems(toolBarItems, animated: true)
}//End viewDidLoad
func toHome() {
let homeVC = HomeViewController(nibName: "HomeViewController", bundle: nil)
self.pushViewController(homeVC, animated: true)
}
func toGame() {
let gameVC = GameViewController(nibName: "GameViewController", bundle: nil)
self.pushViewController(gameVC, animated: true)
}
}
Did you create a second .swift file for your dependent controller? You should move this code to the dependant controller file
self.navigationController?.toolbarHidden = false
let button1 = UIBarButtonItem(title: "home", style: .Plain, target: self, action: #selector(SecondViewController.home))
let myToolBar = [button1]
self.setToolbarItems(myToolBar, animated: true)
I am not sure but I think your buttons has size 0. So maybe you should add some constraints or view frame size. You can try debugging using the view hierarchy debugger.
Maybe you just have to replace this self.navigationController?.toolbarHidden = false
With this toolbarHidden = false
I'm confused by your code. Is the class you show us, the one Navigation Controller where all other ViewController depend on or is it itself one dependent ViewController that in this case appears to be a Navigation Controller? Or is it a Navigation Controller by mistake? (not very likely)
Why I ask? At one time you're referring to the parent navigation controller with self.navigationController?.toolbarHidden = false which is not this navigation controller itself. Then in the rest of the code, you refer to this controller itself.
Hope this leads to the right thinking.

Why LeftBarButtonItem doesn't appear in the navigationbar in swift

I have two view A and view B.
From view A to view B, I do not use navigation controller, I used performSegueWithIdentifier() and I don't want to use navigation controller to pass view A to view B.
But in the view B, I want to add a leftBarButtonItem in the navigation bar(I have embed a navigation controller for view B) like a back button with a arrow.
In order to achieve 100% same with the system backbitten with arrow. I use NSMutableAttributedString and UIButton. code is below:
let string = "< Retour" as NSString
var attributedString = NSMutableAttributedString(string: string as String)
let ArrowAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor(), NSFontAttributeName: UIFont.systemFontOfSize(20)]
let TextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor(), NSFontAttributeName: UIFont.systemFontOfSize(10)]
attributedString.addAttributes(ArrowAttributes, range: string.rangeOfString("<"))
attributedString.addAttributes(ArrowAttributes, range: string.rangeOfString(" Retour"))
let backbutton = UIButton(type: .Custom)
backbutton.addTarget(self, action: "back:", forControlEvents: .TouchUpInside)
backbutton.setAttributedTitle(attributedString, forState: UIControlState.Normal)
self.navigationItem.setLeftBarButtonItem(UIBarButtonItem(customView: backbutton), animated: true)
rightBtn = UIBarButtonItem(title: "Ok", style: .Plain, target: self, action: "save:")
But I can not see left button in the navigation bar in view B…why I can not see it in the navigation bar? Why the left button disappear?
Thank you very much.
I have tried the new code for a label, but it doesn't work yet...
let barButtonBackStr = "< Back"
let attributedBarButtonBackStr = NSMutableAttributedString(string: barButtonBackStr as String)
attributedBarButtonBackStr.addAttribute(NSFontAttributeName,
value: UIFont(
name: "AmericanTypewriter-Bold",
size: 18.0)!,
range: NSRange(
location:0,
length:1))
let label = UILabel()
label.attributedText = attributedBarButtonBackStr
label.sizeToFit()
let newBackButton = UIBarButtonItem(customView: label)
self.navigationController!.navigationItem.setLeftBarButtonItem(newBackButton, animated: true)
Thank you
Try a backbutton.sizeToFit() you'll see your button
You create a button but you never set the frame
You can also set the frame directly instead of sizeToFit() method like backbutton.frame = CGRectMake(0, 0, 100, 20)
PS: TextAttributes wasn't used
You must write it to :
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
...
}
Try to set a breakpoint after your UI design and try to launch the Debug View Hierarchy to see if your button exist or is hidden by another object
Next, after you have set your button try to make:
self.navigationController!.navigationItem.leftBarButtonItem.customView.sizeToFit()