UIBarButtonItem not firing selector after it has been shown twice - ios

I use this category method on UIBarButtonItem to create custom buttons as follows:
+ (UIBarButtonItem*)itemWithImage:(UIImage*)image forState:(UIControlState)controlState target:(id)target action:(SEL)action{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:image forState:controlState];
button.frame= CGRectMake(0.0, 0.0, 44, 44);
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
UIView *v=[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 44, 44) ];
[v addSubview:button];
return [[UIBarButtonItem alloc] initWithCustomView:button];
}
I then create the buttons and assign them to the navigation item in my view controller as follows:
-(void)viewDidLoad{
[super viewDidLoad];
UIBarButtonItem * cancelButtonItem = [UIBarButtonItem itemWithImage:[UIImage imageNamed:#"Cancel"] forState:UIControlStateNormal target:self action:#selector(cancel)];
self.navigationItem.leftBarButtonItem = cancelButtonItem;
UIBarButtonItem * checkmarkButtonItem = [UIBarButtonItem itemWithImage:[UIImage imageNamed:#"checkmark_active"] forState:UIControlStateNormal target:self action:#selector(done)];
self.navigationItem.rightBarButtonItem = checkmarkButtonItem;
}
The first time I create a view controller and push it, the button works, but when creating a brand new view controller and pushing it onto the navigation stack, it breaks. Any ideas? I have thoroughly debugged this and am out of ideas.

There doesn't appear to be anything wrong with the category section of your code. I suspect that the error might be stemming from something else. Some more information or code may help here... what do you mean by break etc.
Check the way you initialise the ViewController before you push it onto the stack, perhaps a simple syntax error or mistaken nib name if using outlets.

Related

Reloading navigation bar

How can I reload/reassign navigation bar items? I use some libraries that change navigation bar and sometimes I have a bag in which all navigation items disappear. I have reassigned right items in viewWillAppear like:
UIButton *actionButton = [UIButton buttonWithType:UIButtonTypeCustom];
actionButton.frame = CGRectMake(270, 0, 50, 50);
actionButton.adjustsImageWhenHighlighted = YES;
[actionButton setImage:[UIImage imageNamed:#"share.png"] forState:UIControlStateNormal];
[actionButton setImage:[UIImage imageNamed:#"share-active.png"] forState:UIControlStateHighlighted];
[actionButton addTarget:self action:#selector(presentActivity) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *actionBarButton = [[UIBarButtonItem alloc]initWithCustomView:actionButton];
actionBarButton.tintColor = [UIColor whiteColor];
self.navigationItem.rightBarButtonItem = actionBarButton;
But it does not work and sometimes I do not have any navigation items.
UIBarButtonItem
is not child of UIButton.
here is not known methods like setImage:forState: etc.
create and custon an UITabBarButton like this
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStyleBordered target:self action:#selector(goBack)];
newBackButton.image = [UIImage imageNamed:#"back"];
self.navigationItem.leftBarButtonItem=newBackButton;
also verify if method with this code will be called when viewDidLoad
Check out this like https://developer.apple.com/library/ios/documentation/uikit/reference/uinavigationbar_class/Reference/UINavigationBar.html the apple dev is awesome.
This is another good link
AppCoda has a lot of great tutorials this one has everything you need to know about Nav Bars
http://www.appcoda.com/customize-navigation-status-bar-ios-7/
and you could also use perform segue with identifier method and to send a string or something to a new view controller and then when you see that string is equal to what you want use an if statement in your viewWillAppear method.

Changing Navigatiobar back button action in ios6/ ios 7 compatible applications

I have a navigation controller application, and I need to set the custom action for the navigation back bar button. Tried some workarounds and not yet to find a solution.
Tried
UIBarButtonItem *backBarItem = self.navigationItem.leftBarButtonItem;
backBarItem.target = self;
backBarItem.action = #selector(popToHomeViewController);
Result : No effect. Back button pops to just previous viewController in navigation stack
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithTitle:backBarItem.title style:backBarItem.style target:self action:#selector(popViewController)];
self.navigationItem.leftBarButtonItem = customBarItem;
Result : No effect. Back button pops to just previous viewController in navigation stack
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithTitle:#"back" style:backBarItem.style target:self action:#selector(popViewController)];
self.navigationItem.leftBarButtonItem = customBarItem;
Result:Now my selector got invoked perfectly and navigated to desired viewController. Here the issue is that the back button not as like as the native back button. It is not having the bold "<" character as I have not mentioned it. If added < character it needs to be changed for ios 6 compatibility.
Any better solution to ensure ios 6 and ios 7 compatible navigation back button with custom selector?
Try this simple example will help you..
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *buttonImage = [UIImage imageNamed:#"back.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:buttonImage forState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, buttonImage.size.width, buttonImage.size.height);
[button addTarget:self action:#selector(back) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:button];
self.navigationItem.leftBarButtonItem = customBarItem;
[customBarItem release];
}
-(void)back {
[self.navigationController popViewControllerAnimated:YES];
}
Make sure you have an button image with the size of a navigation bar back button in your resource folder with name back.png
Feel free if any other assistance is required.
Happy Coding!!!!!
Try this
viewController.navigationItem.hidesBackButton = YES;
//set custom image to button if needed
UIImage *backButtonImage = [UIImage imageNamed:#"back"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:backButtonImage forState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, backButtonImage.size.width, backButtonImage.size.height);
[button addTarget:viewController action:#selector(back) forControlEvents:UIControlEventTouchUpInside];
UIView *backButtonView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, backButtonImage.size.width, backButtonImage.size.height)];
[backButtonView addSubview:button];
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:backButtonView];
viewController.navigationItem.leftBarButtonItem = customBarItem;
and in back method you can customise
- (void)back {
//Your code
}

How to create re-usable code in iOS for a custom back button

I have created a custom back button (code below). I've so far been re-pasting this block of code all through my app on every single page. I was wondering if someone could take my code as an example and give me pointers on how to throw this into one centralized location so that I wouldn't have to copy and paste it anymore.
I'm guessing this would go into a custom class .h and .m that I'd create but I'm not exactly sure what to do next as far as what the code itself would look like within the custom files.
// Create custom back button
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *backButtonImage = [UIImage imageNamed:#"back.png"];
[backButton setBackgroundImage:backButtonImage
forState:UIControlStateNormal];
[backButton addTarget:self
action:#selector(backButton)
forControlEvents:UIControlEventTouchUpInside];
[backButton setFrame:CGRectMake(0, 0, 40, 40)];
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
[[self navigationItem] setLeftBarButtonItem:backButtonItem];
I would probably go with a category on UIViewController, with an interface like this:
#interface UIViewController (MyBackButton)
- (void)installBackButtonWithAction:(SEL)action;
#end
The implementation is the code from your question, with #selector(backButton) replaced by action:
#import "UIViewController+MyBackButton.h"
#implementation UIViewController (MyBackButton)
- (void)installBackButtonWithAction:(SEL)action {
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *backButtonImage = [UIImage imageNamed:#"back.png"];
[backButton setBackgroundImage:backButtonImage
forState:UIControlStateNormal];
[backButton addTarget:self
action:action
forControlEvents:UIControlEventTouchUpInside];
[backButton setFrame:CGRectMake(0, 0, 40, 40)];
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
[[self navigationItem] setLeftBarButtonItem:backButtonItem];
}
#end
You might call it like this, for example:
- (void)viewDidLoad {
[super viewDidLoad];
[self installBackButtonWithAction:#selector(backButton)];
}
You could create a subclass of UINavigationController and have it be alter the navigationItem of any view controller that's pushed Ito its stack to set the custom back button. Then you just create an instance of your custom class instead of your current use of UINavigationController and every view controller will automatically get updated.
You could put that code into a category somewhere; given you're setting self as the target, `UIViewController might work. But, thats kind of ugly and relies on an assumption that your dismissal action will never change.
Something cleaner that you could do is refactor it a bit so that you create the button by passing in the target (self) and dismissal action (backButton) and have the category on UIBarButton instead.

How to prevent animation of back button when switching views?

I cannot figure out how to disable the back-button animation that occurs in the navigation bar when switching from a tableview to a standard view (when a cell is selected). There is no obvious line of code that enabled animation to begin with. Here it is in gif-form:
The navigation buttons in the Facebook app do not animate, so it is possible.
It may be relevant to mention that I am using the ViewDeck library to create the Facebook-like tableView menu, i.e. swipe to the right to expose a table.
EDIT: solution is based on Hesham Abd-Elmegid's answer but modified to use a custom image...
UIImage *settingsImage = [UIImage imageNamed:#"back_button#2x.png"];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
backButton.frame = CGRectMake(280.0, 10.0, 29.0, 29.0);
[backButton setBackgroundImage:settingsImage forState:UIControlStateNormal];
backButton.frame = CGRectMake(0, 0, 50, 30);
[backButton addTarget:self action:#selector(goBack) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
self.navigationItem.leftBarButtonItem = customBarItem;
If you set a custom UIBarButtonItem as a left navigation item (instead of standard back button item), it will fade instead of slide in, just like in Facebook's app. Just create a simple method that will replace back button functionality by calling popViewControllerAnimated: on the navigation controller in which your detail view controller is contained.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:self action:#selector(goBack)] autorelease];
}
- (void)goBack
{
[self.navigationController popViewControllerAnimated:YES];
}
Note: UIBarButtonItem can also be set up with an image using initWithImage:style:target:action: method.
You could replace the back button with a custom UIButton. That way it won't animate on transition.
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:#"Back" forState:UIControlStateNormal];
backButton.frame = CGRectMake(0, 0, 50, 30);
[backButton addTarget:self action:#selector(onBack) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
self.navigationItem.leftBarButtonItem = customBarItem;
[customBarItem release];
You will have to find a PNG for the arrow shape of the back button though.

Why won't this UIButton display as my leftBarButtonItem, UIBarButtonItem seems to be set properly

In my RootViewController, I set an image as a rightBarButtonItem exactly like this, but in this second ViewController I created, this "back" button won't display. I run it on the simulator and on my iPhone and I can tap the area where the button should be showing up and the goBack{} method is being called. Just the image(s) aren't showing. Any thoughts?
Also, as far as the images go, I'm exporting them the exact same way I've been exporting all my other images. All the others have been working fine. It doesn't seem like a problem with the images, as I've substituted the back button images for several others and none of them are displaying. I'm pretty sure I'm creating these images in the right order. Anyway, any help would be much appreciated.
From my NewGameViewController.m file:
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat startingPoint = 0.0;
CGRect bounds = self.view.bounds;
bounds.origin.y = startingPoint;
bounds.size.height -= startingPoint;
self.ivarNewGameTableView = [[UITableView alloc] initWithFrame:bounds style:UITableViewStyleGrouped];
self.ivarNewGameTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.ivarNewGameTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.ivarNewGameTableView];
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background.png"]];
self.ivarNewGameTableView.backgroundView = backgroundImageView;
UIImage *mainNavBar = [UIImage imageNamed:#"startNewGameNavBar.png"];
UIImageView *navBarView = [[UIImageView alloc] initWithImage:mainNavBar];
[navBarView setFrame:CGRectMake(0.0, 0.0, 320.0, 44.0)];
[self.navigationController.navigationBar addSubview:navBarView];
UIButton *back = [UIButton buttonWithType:UIButtonTypeCustom];
// neither one of the following lines work. I know they're supposed to be identical, but
// seen Xcode be picky.
back.frame = CGRectMake(0.0, 0.0, 54.0, 36.0);
// [back setFrame:CGRectMake(0.0, 0.0, 54.0, 36.0)];
[back addTarget:self action:#selector(goBack) forControlEvents:UIControlEventTouchUpInside];
[back setImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[back setImage:[UIImage imageNamed:#"backTouched.png"] forState:UIControlStateHighlighted];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:back];
self.navigationItem.leftBarButtonItem = backButton;
}
-(void)goBack {
NSLog(#"goBack called.");
// [self.ivarNewGameTableView pushViewController:];
}
If you're in a navigation stack the back button item is set for you. Use backBarButtonItem correctly do get the behaviour you like.
On your main view controller that you want to come back to you need to overload the backBarButton item.
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle: #"Back" style: UIBarButtonItemStyleBordered target: nil action: nil];
self.navigationItem.backBarButtonItem = newBackButton;
Some code samples on github
Ok. Finally figured this out. The problem was with this line in the creation of my New Game View Navigation Bar:
[self.navigationController.navigationBar addSubview:navBarView];
I did this in my Root View's Navigation Bar too. It now looks like this, in both files:
UIImage *startNewGameNavBar = [UIImage imageNamed:#"startNewGameNavBar.png"];
// with the key line being this one
[self.navigationController.navigationBar setBackgroundImage:startNewGameNavBar forBarMetrics:UIBarMetricsDefault];
In noob-speak, as I wish more programmers would use for noobs like me, if you're having problems with buttons disappearing behind the your custom navigation bar, and you're using code that looks like my example, it's because you're not supposed to be adding it as a subview. This puts it on top of everything else. Instead, change the navigation bar's background image and, of course, the image winds up in the...(drumroll, please)...background. (end drumroll)
As for the adding of the button images, I just created a UIButton with custom type, set the images for the normal and highlighted states, set the button to call my goBack method, set its frame size, and assigned it to the navigationItem's leftBarButtonItem property:
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[backButton setImage:[UIImage imageNamed:#"backTouched.png"] forState:UIControlStateHighlighted];
[backButton addTarget:self action:#selector(goBack) forControlEvents:UIControlEventTouchUpInside];
[backButton setFrame:CGRectMake(0.0, 0.0, 54.0, 36.0)];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];

Resources