Popover crashing on UIBarButtonItem action in iOS - 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)
}

Related

Use only custom image for navigationItem backBarButton Item

I want to remove the title and use only custom image for back button in Navigation Controller.
I came across questions like this and I have tried this:
navigationItem.backBarButtonItem = UIBarButtonItem(image: UIImage(named: Constants.Image.kClose), style: .plain, target: nil, action: nil)
I am putting this in viewDidLoad() of the View Controller which is pushing a UITabbarController. ( I know its not a very good idea to push Tab Bar in a Navigation Controller, but I need to do this).
I am getting the following result:
But I don't want that default blue back button. I just want my custom close button to appear there. How can I achieve this?
Create a bar button
- (UIBarButtonItem *)backButton {
UIButton *leftButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 4, 34, 34)];
leftButton.layer.cornerRadius = leftButton.frame.size.width / 2;
leftButton.layer.masksToBounds = YES;
[leftButton setImage:[UIImage imageNamed:#"back"] forState:UIControlStateNormal];
[leftButton addTarget:self action:#selector(backButtonTapped) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *leftBarButton = [[UIBarButtonItem alloc] initWithCustomView:leftButton];
return leftBarButton;
}
and set like this
self.navigationItem.leftBarButtonItem = [self backButton];
self.navigationController?.navigationBar.backIndicatorImage = backImage
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = backImage
self.navigationController?.navigationBar.backItem?.title = ""
UIBarButtonItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.clear], for: .normal)
UIBarButtonItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.clear], for: UIControl.State.highlighted)

Custom BackButton on NavigationController not appearing

I'm trying to use a custom back button in UINavigationController but the image is not appearing.
Here's the code:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.translucent = true
self.navigationController!.view.backgroundColor = UIColor.clearColor()
self.navigationController?.navigationBar.backIndicatorImage = UIImage(named: "Back-50")
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "Back-50")
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
I'm not sure what's going wrong with this code.
Maybe, you should use UIAppearance.
Like this
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UINavigationBar appearance] setBackIndicatorImage: [UIImage imageNamed:#"icon-back"]];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage: [UIImage imageNamed:#"icon-back"]];
return YES;
}
In swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "")
UINavigationBar.appearance().backIndicatorImage = UIImage(named: "")
return true
}
If you want just your image to appear as the back button then set the tintColor of the navigationBar to clear color and then set an image based UIBarButtonItem as the backBarButtonItem of navigationItem of the controller.
let backButton = UIBarButtonItem(image: UIImage(named: "back"), style: .Plain, target: self, action: "back")
self.navigationController?.navigationBar.tintColor = UIColor.clearColor()
self.navigationItem.backBarButtonItem = backButton
This will make the default back button image (<) not appear (infact it appears but its in clear color so not visible) and just show the back image.
You have to implement those line of code in the targeted viewcontroller that means the controller you will push, because you want to customize back item button which active only when you push a viewcontroller into navigation controller stack. Your code works for me.
navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "Back-50"), style: .Plain, target: self, action: "back")
func back(){
self.navigationController?.popViewControllerAnimated(true)
}
Try this
self.navigationItem.hidesBackButton = YES;
UIButton *btnLeft=[UIButton buttonWithType:UIButtonTypeCustom];
btnLeft.frame=CGRectMake(0, 0, 65, 40);
[btnLeft addTarget:self action:#selector(onClickBackBarItem:) forControlEvents:UIControlEventTouchUpInside];
[btnLeft setImage:[UIImage imageNamed:#"image_name"] forState:UIControlStateNormal];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:btnLeft];
-(void)onClickBackBarItem:(id)sender
{
// ** your stuff ** //
}
May this help yoy
Try this it`s working for me.
var BackButton : UIBarButtonItem = UIBarButtonItem(image:
UIImage(named: "Back-50"), style: .Plain, target: self, action: "back")
self.navigationItem.leftBarButtonItem = BackButton
func back()
{
// your backcontroller code here....
}

How can I add UIBarButtonItem to my navigation controller programmatically?

I want to add UIBarButtonItem to my navigation controller programmatically in both left and right side and change both of them to other UIBarButtonItems when clicked. And also I want to use my item icons. Can i do that? Its my 2nd week in iOS programming excuse me if its a simple question
With image:
self.navigationItem.setLeftBarButtonItem( (UIBarButtonItem(image:UIImage(named:"image"), style: .Plain, target:self, action:"action:")), animated: false)
With title:
self.navigationItem.setLeftBarButtonItem( (UIBarButtonItem(title:"backButton", style: .Plain, target:self, action:"back_pressed:")), animated: false)
Furthermore, you can assign multiple items for each side:
var test: UIBarButtonItem = UIBarButtonItem(image: UIImage(named:"test"), style: UIBarButtonItemStyle.Plain, target: self, action: "test1:")
var test2: UIBarButtonItem = UIBarButtonItem(image: UIImage(named:"test2"), style: UIBarButtonItemStyle.Plain, target: self, action: "test2:")
navigationItem.rightBarButtonItems = [test1, test2]
When using multiple items you might be interested in:
var spacing : UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
which is used to have similar space between buttons.
Objective-C version
UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"close"] style:UIBarButtonItemStylePlain target:self action:#selector(back:)];
self.navigationItem.leftBarButtonItem = closeButton;
//OR
UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithTitle:#"Close" style:UIBarButtonItemStylePlain target:self action:#selector(back:)];
self.navigationItem.leftBarButtonItem = closeButton;
try this code-
self.title = "Title"
var left : UIBarButtonItem = UIBarButtonItem(title: "LeftButtonTitle", style: UIBarButtonItemStyle.Plain, target: self, action: "")
var right : UIBarButtonItem = UIBarButtonItem(title: "RigthButtonTitle", style: UIBarButtonItemStyle.Plain, target: self, action: "")
self.navigationItem.leftBarButtonItem = left
self.navigationItem.rightBarButtonItem = right

Unable to display Toolbar items in a NavigationController using Swift

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
}

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