I need a few information about UINavigationControllers/UIBarButtonItems - objective-c

I guess this question may sound very noobish for a lot of people around here. But I'm still beginner at iOS dev and even though I'm improving, some things stay confuse for me. 
The menu of my app has the following config : a Navigation Controller containing a Navigation Bar, and embedding a View Controller that contains a Navigation Item btw. 
My Navigation Bar subclasses UINavigationBar to make it look like as I want. 
Now, I just want to add a custom BarButtonItem with a i (information), I already drawn it. So that is my question : how can I add this button ?
Thanks a lot for your advices. 

// Create the Info button
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
// Give it an action handler
[infoButton addTarget:self
action:#selector(infoButtonAction:)
forControlEvents:UIControlEventTouchUpInside];
// Create a UIBarButtonItem to "contain" the Info button
UIBarButtonItem *infoItem = [[UIBarButtonItem alloc] initWithCustomView:infoButton];
// Add the UIBarButtonItem to the navigation bar (on the left side)
[self.navigationItem setLeftBarButtonItem:infoItem animated:NO];
Action handler:
- (void)infoButtonAction:(id)sender {
NSLog(#"Tapped on info button!");
}

This may not be an answer to your question directly, but it'd probably prevent problems if you were using UINavigationController as it was meant to be used. Rather than subclassing UINavigationBar to customize its interface, just use its UIAppearance methods, and then create a UINavigationController like normal.
// Create navigation controller.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:myViewController];
// Customize navigation bar appearance.
[[UINavigationBar appearance] setTintColor:[UIColor blueColor]];
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"navigation-bar-background"] forBarMetrics:UIBarMetricsDefault];

Related

Setting uinavigationitem's back button not working

After reading a bunch of similar questions on SO I've found out that in order to use a custom back button view I should be setting the nav controller's nav bar's nav item's left button item to a custom view, but no matter what I do I'm getting stuck with the default. I've tried setting this both inside the view controller I want to navigate back from, as well as the one I'm navigating back to, to no avail. Any ideas what I might be doing wrong?
- (void)loadView{
[super loadView];
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc]initWithCustomView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"back-btn"]]];
self.navigationController.navigationItem.leftBarButtonItem = backButtonItem;
self.navigationController.navigationItem.leftBarButtonItem.tintColor = [UIColor whiteColor];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
The key thing you’re doing wrong is using the bar button item on the navigation controller instead of on your view controller. To quote Apple’s View Controller Catalog for iOS:
In a navigation interface, each content view controller in the navigation stack provides a navigation item as the value of its navigationItem property.
Emphasis mine; the content view controller is your custom view controller. Try this:
self.navigationItem.leftBarButtonItem = backButtonItem;
You need to do this in all your view controllers that should have the custom button, so I recommend creating your own base view controller class that subclasses UIViewController and implements custom back buttons, and use this base view controller as the parent of your other view controllers.
You’re hiding the navigation bar, which probably isn’t a good idea if you want it to show a custom back button.
By replacing the standard back button, you lose its tap behaviour. Use a UIButton in the bar button item’s custom view instead of a UIImageView.
Also, it would be more conventional to put this setup code in viewDidLoad rather than loadView.
So I would do something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setBackgroundImage:[UIImage imageNamed:#"back-btn"] forState:UIControlStateNormal];
[backButton sizeToFit];
[backButton addTarget:self action:#selector(popNavigationController:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
self.navigationItem.leftBarButtonItem = backButtonItem;
}
- (void)popNavigationController:(id)sender
{
[[self navigationController] popViewControllerAnimated:YES];
}
Note that if you use a custom back button, the swipe-from-the-edge-of-the-screen-to-go-back gesture will not work. See this Stack Overflow question for a couple of potential solutions, but it’s fiddly.

How to change MFMessageComposeViewController's Contact picker's title color and text?

I'm using MFMessageComposeViewController in my application to present the sending sms feature within the app using the following code.
MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
picker.messageComposeDelegate = self;
[self presentModalViewController:picker animated:YES];
[picker release];
Also you need to import its delegate and header file in .h file as,
#import <MessageUI/MessageUI.h>
...
#interface YourViewController : UIViewController <....., MFMessageComposeViewControllerDelegate>
The sms view controller will look like..
Problem:
The problem is, I used a custom color throughout my app. That color was getting reflected in this sms view controller's navigation bar color like this..
But I do not want to show the custom title color here. I just want to show the default one. Is it any way to change this custom title color to the default one?
Note: I added the custom navigation title color in Appdelegate's didFinishLaunchingWithOptions method
You can use UIAppearance appearanceWhenContainedIn and then add your classes that are applicable.
I got the solution by following code..
[[UINavigationBar appearanceWhenContainedIn:[ABPeoplePickerNavigationController class], nil] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearanceWhenContainedIn:[ABPeoplePickerNavigationController class], nil] setBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
Here, I just define nil to the background color of ABPeoplePickerNavigationController class. All other classes in my application will have the same navigation bar color and same back button's color (that is, custom color that I added to the navigation bar's appearance in AppDelegate).

How can I set barButtonItems in a uiSplitViewController in iOS 5.1?

I am using the Master-Detail template from XCode 4.3.1 and want to access the toolbar on the detailView control.
[self navigationItem] setTitle:
sets the title, but I can't figure out how to add barButtonItems either through the xib or programmatically. In the past, with an earlier SplitView Template (when master view was called root view) I could access the rootView toolbar through the Split View Controller in MainWindow.xib and I had the detailView toolbar right there in the detailView.xib file.
What is the best way for me to set these items (I have 4) on the detailView toolbar?
Thanks in advance.
So I've got an answer - please let me know if you have a better one!
In the viewDidLoad method of my masterViewController I populated the toolbar on the detail view with
[_detailViewController.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects: _detailViewController.firstButton, _detailViewController.secondButton, _detailViewController.thirdButton, nil]];
I had created these buttons with
_detailViewController.firstButton = [[UIBarButtonItem alloc] initWithTitle:#"First" style:UIBarButtonItemStylePlain target:self action:#selector(firstButtonAction:)];
I had declared each of these buttons in the detailViewController.h file so that I could reference them later, but probably didn't need to use those names - it just made the code longer here. I also had a uiButton that I could not add in the array of buttons, so I created a the button, put it inside a View and then set that as the titleView for the navigation item:
_detailViewController.biggerButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 230, 35)];
[[_detailViewController biggerButton] addTarget:self action:#selector(biggerButtonTap:) forControlEvents:UIControlEventTouchUpInside];
UIView *biggerButtonView = [[UIView alloc] initWithFrame:CGRectMake(80, 3, 230, 35)];
[biggerButtonView addSubview:_detailViewController.biggerButton];
_detailViewController.navigationItem.titleView = biggerButtonView;

iOS: Trying to add Navigation Bar to Modal UITableViewController

I'm following the CoreDataRecipes app for modaly showing the add screen when I want to add a new item. However I cannot get the bar to display at the top so I can press 'Done' or 'Cancel'.
In the xib calling the modal controller I have the + button linked to modally sliding up the controller via IB.
I have the below in my modal controller
self.navigationItem.title = #"Add";
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:self action:#selector(cancel)];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Save" style:UIBarButtonItemStyleDone target:self action:#selector(save)];
self.navigationController.navigationBarHidden = NO;
In my viewDidLoad
The modal controller displays fine except there is no bar so I cannot leave that screen.
You need to add it before the popover is actually presented.
Where you create the modal popover, you need to create it inside a UINavigationController first.
So, do the following.
PopoverView *foo = [[PopoverView alloc] initWithNibName:#"PopoverView" bundle:nil];
// Here you pass through properties if you need too.
// ...
UINavigationController *navC = [[UINavigationController alloc] initWithRootView:foo];
[foo release];
[self.navigationController presentModalViewController:navC animated:YES];
That will give the modal view the navigation bar which you're trying to edit.
Alternatively, you could maintain your storyboard segue. In Xcode, select the view controller you are trying to transition to and embed it in a navigation controller.
Now in the viewDidLoad of that view controller, add:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:self action:#selector(cancel)];
and lastly the callback:
- (void)cancel {
[self dismissModalViewControllerAnimated:YES];
}
Or if you just need the look of the bar, not exactly its functionality, you could drag the Navigation Bar (UINavigationBar) or Toolbar (UIToolbar) controll from the Media Library panel onto your view and go from there.
I had a similar predicament whereby I was loading a UITableViewController in a containerView. The containerView was inside a UIViewController which was being presented in a modal fashion.
I, like you, needed the navigation bar to have a title and a Done/Cancel button.
After overflowing the stack, I finally did this -
Dragged a UIView as the first item in the Table View in the IB. This automatically took a height of 44 pts and snapped to the top. It also shifted my first section downwards.
I dragged a UIButton (Done button) inside this view. Created an IBOutlet to it and called
[self dismissViewControllerAnimated:YES completion:nil];
Disclaimer:
1) This fake nav-bar will scroll along with the tableview.
2) This might not be a solution for what Bot has asked, but it's an option for others who might be looking for something similar.

UINavigationBar right button not showing up

I am using the following function via a notification to load a right button on my UINavigationBar, and even though I can trace out the button and verify it is allocated, it does not show up...any ideas?
EDIT 4/6/2011, 2:42PM
So, something interesting...the width always reports as 0.0...
- (void)showRightBarButton:(id)sender
{
NSLog(#"Showing button");
UIBarButtonItem *button = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(showPI:)];
[button setTitle:#"This Button"];
self.navigationItem.rightBarButtonItem = button;
//[[self.navigationItem rightBarButtonItem] setWidth:50];
NSLog(#"Button width is %f.", self.navigationItem.rightBarButtonItem.width);
[button release];
}
[self.view setNeedsDisplay];
You're right. That line isn't needed. As far as the rest of the code goes I don't see what's wrong with it. The only thing I've come up with so far is that self isn't the currently displayed view controller or that you're missing a navigation controller. Perhaps you've created your UINavigationBar yourself instead of using a navigation controller?
Anyway, for easier debugging I would suggest the following:
- (void)showRightBarButton:(id)sender
{
NSLog(#"Showing button");
UIBarButtonItem *button = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(showPI:)];
self.navigationItem.rightBarButtonItem = button;
[button release];
}
EDIT: The width isn't interesting. It's always 0.0 unless you specify it yourself.
The problem is that you're adding the button in the wrong place. You're not supposed to add the button to the navigation item of the navigation controller, but to the navigation item of the controller that is currently displayed by the navigation controller.
You say you're using an NSNotification to trigger the addition of the bar button item. Where are you registering for the notification? Is it possible that the notification is being received before your view is loaded?
If you're registering for notifications in -init you may want to set a flag on your view controller that you should be displaying the bar button item and then reference that flag in -viewDidLoad to optionally display it.
Or you could just register for the notification in -viewDidLoad.