Unable to display Toolbar items in a NavigationController using Swift - ios

I am trying to display toolbar items at the bottom of TableViewController which is inside a Navigation Controller. I’ve written this code in Swift.
I've used Xcode default master-detail template to create the project and written the below code in ViewDidLoad method of MasterTableViewController.
Please help me to fix the issue.
Please find below code snippet.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.addToolBar();
}
func addToolBar ()->Void {
self.hidesBottomBarWhenPushed = false
var toolBarItems = NSMutableArray()
var systemButton1 = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Play, target: nil, action: nil)
toolBarItems.addObject(systemButton1)
var systemButton2 = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
toolBarItems.addObject(systemButton2)
var systemButton3 = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Trash, target: nil, action: nil)
toolBarItems.addObject(systemButton3)
self.navigationController?.toolbarHidden = false
self.setToolbarItems(toolbarItems, animated: true)
//self.navigationController?.toolbarItems = toolbarItems;
}
But Interestingly, the same code written in Objective-C works and shows the toolbar at the bottom with two items
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
[self addToolbar];
}
-(void) addToolbar
{
self.hidesBottomBarWhenPushed = NO;
NSMutableArray *items = [[NSMutableArray alloc] init];
UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay target:nil action:nil];
[items addObject:item1];
UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[items addObject:item2];
UIBarButtonItem *item3 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:nil action:nil];
[items addObject:item3];
self.navigationController.toolbarHidden = NO;
// self.navigationController.toolbarItems = items;
//
[self setToolbarItems:items animated:YES];
}

You have a tiny typo in your code. I highlighted the difference for you:
var toolBarItems = NSMutableArray()
// ^
// [...]
self.setToolbarItems(toolbarItems, animated: true)
// ^
Your code does basically this (with an animation):
self.toolbarItems = self.toolbarItems
Your set the toolbarItems array to the current toolbarItems array, which is empty.
when you use self.setToolbarItems(toolBarItems, animated: true) it will work.

Using NSMutableArray gave me error, the below code worked for me
func setUpToolbar(){
var toolBarItems = [UIBarButtonItem]()
let systemButton1 = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Play, target: nil, action: nil)
toolBarItems.append(systemButton1)
let systemButton2 = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
toolBarItems.append(systemButton2)
let systemButton3 = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Trash, target: nil, action: nil)
toolBarItems.append(systemButton3)
self.setToolbarItems(toolBarItems, animated: true)
self.navigationController?.toolbarHidden = false
}

Related

Stripe iOS change back button title

There's a way to change the Stripe cancel button title?
I need to change it to "Back", in fact, "Back" is a better word to describe its behavior.
I am presenting the controller of this way:
let customerContext = STPCustomerContext(keyProvider: StripeClient.shared)
let paymentMethodsViewController = STPPaymentMethodsViewController(configuration: STPPaymentConfiguration.shared(), theme: STPTheme.default(), customerContext: customerContext, delegate: self as STPPaymentMethodsViewControllerDelegate)
let navigationController = UINavigationController(rootViewController: paymentMethodsViewController)
present(navigationController, animated: true)
Go to STPCoreViewController.m in stripe files.
Just Replace this Method
- (void)commonInitWithTheme:(STPTheme *)theme {
_theme = theme;
if (![self useSystemBackButton]) {
self.cancelItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(handleCancelTapped:)];
self.stp_navigationItemProxy.leftBarButtonItem = self.cancelItem;
}
}
With
- (void)commonInitWithTheme:(STPTheme *)theme {
_theme = theme;
if (![self useSystemBackButton]) {
self.cancelItem = [[UIBarButtonItem alloc]
initWithTitle:#"Back"
style: UIBarButtonItemStylePlain
target:self
action:#selector(handleCancelTapped:)];
self.stp_navigationItemProxy.leftBarButtonItem = self.cancelItem;
}
}
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
// first
let backItem = UIBarButtonItem()
backItem.title = "Back"
self.viewControllers.last?.navigationItem.backBarButtonItem = backItem
// then
super.pushViewController(viewController, animated: animated)
}

Swift - Help Converting from Objective C Syntax

I'm trying to replace the UINavigationController BackBarButtonItem with a custom image, and I would like there to be no back icon like it's currently doing here:
I'm taking this picture from another stack post, but something similar is happening with mine
The solution to this was listed here: Remove back arrow in iOS7
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"back-btn"]
style:UIBarButtonItemStylePlain
target:nil
action:nil];
if ([UINavigationBar instancesRespondToSelector:#selector(setBackIndicatorImage:)]) {
[[UINavigationBar appearance] setBackIndicatorImage:[[UIImage alloc] init]];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[[UIImage alloc] init]];
}
The problem is I'm having trouble converting this code to Swift. If anybody could help me that would be greatly appreciated. Thanks in advance!
For getting swipe back feature :
First set delegate in viewDidLoad:
self.navigationController!.interactivePopGestureRecognizer.delegate = self
And then disable gesture when pushing:
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
super.pushViewController(viewController, animated: animated)
self.interactivePopGestureRecognizer.isEnabled = false
}
And enable in viewDidDisappear:
self.navigationController!.interactivePopGestureRecognizer.isEnabled = true
Use below code:
//Hide Default Back Button First
self.navigationItem.setHidesBackButton(true, animated:true);
//Your code to show back button
let backButton = UIButton()
backButton.setImage(UIImage(named: "imagename"), forState: .Normal)
backButton.frame = CGRectMake(0, 0, 30, 30)
backButton.addTarget(self, action: Selector("action"), forControlEvents: .TouchUpInside)
let rightBarButton = UIBarButtonItem()
rightBarButton.customView = backButton
self.navigationItem.leftBarButtonItem = rightBarButton
//Back Button Action
func action()
{
self.navigationController?.popViewControllerAnimated(true)
}
Or you can refer one of the answer
Use following code in swift 2.2 (xocde 7.3) :
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setBackButton()
}
func setBackButton() {
let backImage = UIImage(named:"back_icon") as UIImage!
let backButton = UIBarButtonItem(image: backImage, style:UIBarButtonItemStyle.Plain, target: self, action: #selector(BaseViewController.viewWillDisappearC) )
self.navigationItem.leftBarButtonItem = backButton
}
func viewWillDisappearC() {
self.navigationController?.popViewControllerAnimated(true)
}
}
Use following code in swift 3 :
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setBackButton()
}
func setBackButton() {
let backImage = UIImage(named:"back_icon") as UIImage!
let backButton = UIBarButtonItem(image: backImage, style: UIBarButtonItemStyle.plain, target: self, action: #selector(BaseViewController.viewWillDisappearC) )
self.navigationItem.leftBarButtonItem = backButton
}
func viewWillDisappearC() {
_ = self.navigationController?.popViewController(animated: true)
}
}

Popover crashing on UIBarButtonItem action in iOS

Created a Custom UIBarButtonItem:
UIButton *favButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 42.0, 30.0)];
[favButton setImage:[UIImage imageNamed:#"iphone-navbar-icon-star-normal.png"] forState:UIControlStateNormal];
[favButton addTarget:self action:#selector(actionButtonFavorite:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barBtnFavorites = [[UIBarButtonItem alloc] initWithCustomView:favButton];
And on Button click I am opening a popover.
- (void)actionButtonFavorite:(UIBarButtonItem *)sender
{
self.selectedButtonTag = sender.tag;
favoriteOptionsVC.contentSizeForViewInPopover = CGSizeMake(favoriteOptionsVC.view.frame.size.width, (IS_iOS_VERSION_7?190.0:160.0));
UINavigationController *favoritesNavVC = [[UINavigationController alloc] initWithRootViewController:favoriteOptionsVC];
self.favoritesPopoverController = [[UIPopoverController alloc] initWithContentViewController:favoritesNavVC];
favoriteOptionsVC.containingPopoverController = self.favoritesPopoverController;
[self.favoritesPopoverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
But the app is crashing saying:
[UIButton view]: unrecognized selector sent to instance 0x7a7445e0
Sender is instance of UIBarButtonItem:
Can anyone help?
Of course sender is a UIBarButtonItem, it is implicitly stated in your function. The real sender (the instance that is calling the method) is a UIButton.
Try this:
UIBarButtonItem *barBtnFavorites = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(actionButtonFavorite:)];
To make your "custom" UIBarButtonItem use this:
UIBarButtonItem *barBtnFavorites = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:#"iphone-navbar-icon-star-normal.png"]
style:UIBarButtonItemStylePlain
target:self
action:#selector(actionButtonFavorite:)];
Made a barbutton item like this -
let dotImage = UIImage(named: "dot")?.withRenderingMode(.alwaysOriginal)
let searchImage = UIImage(named: "search")?.withRenderingMode(.alwaysOriginal)
// let shareImageButton = UIBarButtonItem(image: shareImage, style: .plain, target: self, action: #selector(didTapshareImageButton(sender:)))
let dotImageButton = UIBarButtonItem(image: dotImage, style: .plain, target: self, action: #selector(didTapdotImageButton(sender:)))
let searchButton = UIBarButtonItem(image: searchImage, style: .plain, target: self, action: #selector(didTapSearchButton(sender:)))
Added popover on this -
#objc func didTapdotImageButton(sender: UIBarButtonItem){
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ShareVC")
vc.modalPresentationStyle = .popover
let popover: UIPopoverPresentationController = vc.popoverPresentationController!
popover.barButtonItem = sender
popover.delegate = self
sender.image = UIImage(named: "close")?.withRenderingMode(.alwaysOriginal)
present(vc, animated: true, completion:nil)
}

How to add an action to share button in navigation bar with Xcode

I am trying to add an action to my share button in navigation bar but I don't know how and where to define my "shareAction" method. To add share button, I have the following code in viewWillAppear :
UIBarButtonItem *shareButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAction
target:self
action:#selector(shareAction:)];
self.navigationItem.rightBarButtonItem = shareButton;
in your implementation.m file
- (void) viewWillAppear
{
[super viewWillAppear:animated];
UIBarButtonItem *shareButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction
target:self
action:#selector(shareAction:)];
self.navigationItem.rightBarButtonItem = shareButton;
}
-(void)shareAction:(id)sender
{
NSLog(#"share action");
}
Swift
let shareBar: UIBarButtonItem = UIBarButtonItem.init(barButtonSystemItem:.Action, target: self, action: Selector("userDidTapShare"))
self.navigationItem.rightBarButtonItem = shareBar
func userDidTapShare() {
//Implementation goes here ...
}
In Swift 3.0
Write this code in viewDidLoad
let btnShare = UIBarButtonItem(barButtonSystemItem:.action, target: self, action: #selector(btnShare_clicked))
self.navigationItem.rightBarButtonItem = btnShare
Share button action
func btnShare_clicked() {
print("Share button clicked")
}

Change UINavigationBar back button title

In my application I want to use 'Back' text as back button title for every viewcontroller.
I have read so many posts on stackoverflow but got nothing.
I don't want to set leftbarbuttonitem.
Can anyone help me on this simple task.
Thanks,
Do this in the parent view controller not in the child
Swift
navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)
Objetive-C
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationController.navigationBar.topItem.title = #"";
If you are using storyboard you can select the navigation item in the parent view controller and set the button text you want in 'Back Button' field. Remember to set this in the parent view controller, not in the child that is pushed.
Try this hope it will be work
UIBarButtonItem *btn =
[[UIBarButtonItem alloc] initWithTitle:#"New Title"
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
[[self navigationItem] setBackBarButtonItem:btn];
I needed to use self.navigationController.navigationBar.backItem.title = #"";, the difference being that I'm using backItem instead of topItem.
Back Button With Back Arrow
Objective-C
self.navigationController.navigationBar.topItem.backBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#"Title" style:UIBarButtonItemStylePlain
target:nil action:nil];
Swift
self.navigationController?.navigationItem.backBarButtonItem =
UIBarButtonItem(title:"Title", style:.plain, target:nil, action:nil)
Normal Button Without Back Arrow
Objective-C
self.navigationItem.leftBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#"Title"
style:UIBarButtonItemStylePlain target:nil action:nil];
Swift
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title:"Title",
style:.plain, target:nil, action:nil)
Bold Button Without Back Arrow
Objective-C
self.navigationItem.leftBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#"Title"
style:UIBarButtonItemStyleDone target:nil action:nil];
Swift
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title:"Title",
style:.done, target:nil, action:nil)
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
Changes the currently visible Back Button
extension UIViewController {
func setCurrentBackButton(title: String) {
guard let vcCount = self.navigationController?.viewControllers.count else {
return
}
let priorVCPosition = vcCount - 2
guard priorVCPosition >= 0 else {
return
}
self.navigationController?.viewControllers[priorVCPosition].navigationItem.backBarButtonItem = UIBarButtonItem(title: title, style: .plain, target: self, action: nil)
}
swift 2.0:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.topItem?.title = ""
}
Note: It works only if storyboard have a chain of navigation stack.
Other options/changing title:
self.navigationController?.navigationBar.backItem?.title = ""
navigationItem.backBarButtonItem?.title = ""
navigationItem.leftBarButtonItem?.title = ""
Removing navigationItem:
navigationItem.setLeftBarButtonItem(nil, animated: true)
To remove back button title for all view controller add new swift file and copy this extinction to it
import UIKit
extension UIViewController {
static func swizzle(){
let orginalSelector = #selector(viewDidLoad)
let swizzledSelector = #selector(swizzledViewDidLoad)
let orginalMethod = class_getInstanceMethod(UIViewController.self, orginalSelector)
let swizzledMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewDidLoad))
let didAddMethod = class_addMethod(UIViewController.self, orginalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
if didAddMethod {
class_replaceMethod(UIViewController.self, swizzledSelector, method_getImplementation(orginalMethod!), method_getTypeEncoding(orginalMethod!))
}else{
method_exchangeImplementations(orginalMethod!, swizzledMethod!)
}
}
#objc func swizzledViewDidLoad(){
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
swizzledViewDidLoad()
}
}
After that in AppDelegate inside didFinishLaunchingWithOptions, call the swizzle function.
UIViewController.swizzle()
This function is using the objective c runtime to exchange the viewDidLoad method with another one that removes the back button title and then inside it recall the original viewDidLoad.
in AppDelegate in the DidFinishLaunchingWithOptions add this code:
[[UIBarButtonItem appearance]
setBackButtonTitlePositionAdjustment:UIOffsetMake(-1000.0, 0.0)
forBarMetrics:UIBarMetricsDefault];

Resources