Change navigationBar appearance - objective-c

My application flow: AViewController -> BViewController -> CViewController (via navigationController). AViewController and CViewController looks the same, only BViewController looks different.
I did it this way:
/// AppDelegate (should be 'super' settings)
[[UINavigationBar appearanceWhenContainedIn:[ABCNavigationController class], nil] setBackgroundImage:theImage forBarMetrics:UIBarMetricsDefault];
/// BViewController (should apply ONLY to BViewController)
[self.navigationController.navigationBar setBackgroundImage:BImage forBarMetrics:UIBarMetricsDefault];
The problem is that in CViewController i see the image i loaded in BViewController not in appDelegate. How to restore it to appDelegate settings?
I should underline that backgroundImage is one of many elements that i setup, gave it here as example.

In CViewController try setting the navbar's background image to nil in viewWillAppear, cause it reamains set by your BViewController.
[self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];

Related

Modal status bar and navigation bar text colors from UIActivityViewControllers in iOS 7

When I'm using a UIActivityViewController, after the user chooses an activity (such as Mail or Message), I can not change the text color for the status bar nor the text/tint color of the Cancel and Send navigation bar buttons. For the bar buttons, in the AppDelegate I've tried using:
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
And nothing happens. However I am able to set the navigation bar title with this:
[[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor], UITextAttributeTextColor, nil]];
I set the UIViewControllerBasedStatusBarAppearance to NO in the Info.plist. And put the line:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
in the AppDelegate, and have had no luck changing the status bar color at all. Any ideas?
As the UIActivityViewController presents the underlying model view controllers, we use this workaround to fix the status bar color issue:
#interface StatusBarColorApplyingActivityViewController : UIActivityViewController
#end
#implementation StatusBarColorApplyingActivityViewController
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
[super presentViewController:viewControllerToPresent animated:flag completion:^{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
if (completion) {
completion();
}
}];
}
#end
As you can see, this is just a class extending the UIActivityViewController overriding the presentViewController:animated:completion:. When the view controller has been presented we set the status bar style via UIApplication in the completion block. Then we call the original completion block given to the method, if any.
Rather than sub-classing from UIActivityViewController, we can change the tintColor of the navigation bar upon presenting it and revert it upon completion in the completionHandler. For example:
UIColor *normalColor = [[UINavigationBar appearance] tintColor];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
[activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed) {
// back to normal color
[[UINavigationBar appearance] setTintColor:normalColor];
}];
[self presentViewController:activityViewController animated:YES completion:^{
// change color to suit your need
[[UINavigationBar appearance] setTintColor:[UIColor colorWithRed:25.0f/255.0f green:125.0f/255.0f blue:255.0f/255.0f alpha:1.0f]]; // ActionSheet options' Blue color
}];
In iOS 8 the UIActivityViewController presents its individual compose controllers on the root view controller of your application.
You need to subclass your root view controller (whether it be a UIViewController or UINavigationController) and add the following code.
#interface UINavigationControllerBarColor : UINavigationController
#end
#implementation UINavigationControllerBarColor
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
[super presentViewController:viewControllerToPresent animated:flag completion:^{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
if (completion) {
completion();
}
}];
}
#end
and then instead of initializing a UINavigationController in the AppDelegate or storyboard, initialize your newly subclassed controller.
Some other recommendations subclass the UIActivityViewController but this does not work.
If you want to change the bar button and title colors as well use the following in your application:didFinishLaunching:
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
[[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor whiteColor], UITextAttributeTextColor,
[UIFont systemFontOfSize:18.0f], UITextAttributeFont,
nil]];
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTintColor:[UIColor whiteColor]];
I believe the code to change the navigation bar color is this:
[[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]];
This is for changing the colours of the navigation bar buttons in iOS 7, if you might need it:
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
And this is the code if you want to change the colours of the buttons in iOS 6:
[[UIBarButtonItem appearance] setTintColor:[UIColor redColor]];
This code is also for iOS 8+ to change the bar button text color for UIActivityViewController activities (like sharing via Messages or Mail Composer).
I found a solution to change the text color of the Send and Cancel buttons.
Check my answer from here.
Regarding changing the status bar style from black to white, I've tried pretty much everything that is on Stackoverflow and nothing worked. There seems to be no workaround it.
One thing that might work, but I don't really know how to use it, could be changing the status bar style in the child view controller. There's a Stackoverflow post about it here.
This might work only if the assumption that the MFMailComposerViewController and MFMessageComposeViewController are child view controllers of UIActivityViewController and therefore if we specify the status bar style for the UIActivityViewController then the child view controllers should have the same status bar style as the parent.
There's a method in the UIViewController called childViewControllerForStatusBarStyle. Here is the Apple documentation for it .
But I don't really know how to use that. Did anyone figure this out?
You have to set the tintColor of the entire app.
self.window.tintColor = [UIColor redColor];
or
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
bar buttons
self.navigationController.navigationBar.tintColor = [UIColor redColor];

Recipients field of MFMessageComposeViewController doesn't show in iOS 7

The code below works fine in iOS 5/6. In iOS 7, it looks like this (red oval for emphasis).
Code:
if ([MFMessageComposeViewController canSendText]) {
self.messageComposer = [MFMessageComposeViewController new];
self.messageComposer.recipients = #[number];
self.messageComposer.messageComposeDelegate = self;
[self presentViewController:self.messageComposer
animated:YES
completion:nil];
}
Question: This is simple code. Is there some other external property, perhaps of the presenting view controller, that is affecting this? Anyone have a fix or workaround?
thanks.
I've found that the MFMessageComposeViewController's recipient field seems to take some of it's appearance from the UINavigationBar appearance proxy in iOS7. To work around this, I've done the following in my apps:
Create an empty custom UINavigationController subclass, which doesn't override any of UINavigationController's methods.
Use this custom UINavigationController subclass as a marker for any navigation controllers that I want to have custom appearance, by setting the custom class on the identity inspector in IB:
In my app delegate, set up the appearance of navigation bars like this:
[[UINavigationBar appearanceWhenContainedIn:[MyCustomNavigationController class], nil] ...];
This ensures that I get the navigation bar appearance I want in the controllers I want to customize, but preserves the standard navigation bar (and related) appearance in other controllers (like MFMessageComposeViewController). Here's a screenshot; note the standard appearance of MFMessageComposeViewController, with the custom navigation bar appearance on the popover in the background:
I faced same problem and here is my solution-
Before presenting your message composer( [self presentViewController:messageComposer animated:YES completion:nil]; )
set
[[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
and in delegate method
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result {
UIImage *backgroundImage = [UIImage imageNamed:#"Navigation Bar"];
[[UINavigationBar appearance] setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];
[self dismissViewControllerAnimated:YES completion:nil];
}
Thats all!!

Strange Bug in iOS 6 UINavigationController

I have found a strange bug in ios. When I use UINavigationController and push other controllers, the titleView shifted to the right so much as how many controllers was pushed
It's looks like this:
My code is simple:
self.navigationItem.title = #"Test Title";
In the second case, controller has 5th in viewControllers stack. The controller in the all cases is same.
I was using the appearance for UIBarButtonItem, in my AppDelegate.
[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(-1000, 0) forBarMetrics:UIBarMetricsDefault];
I was fix it with some trick =)
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes:#{UITextAttributeFont: [UIFont systemFontOfSize:0.1]}
forState:UIControlStateNormal];

How can i add a custom uibarbuttonItem to my navigation item in all view controllers?

I am trying to add a custom UIBarButtonItem to my navigationItem. This button will be available in all my view controllers. so instead of adding it to each viewDidLoad method in each viewDidLoad I am trying to add it in my application Delegate class in a seperate method that i will call in the viewDidLoad method.
Here is my Code:
UIImage* image = [UIImage imageNamed:#"some-header-icon.png"];
CGRect frame = CGRectMake(0,0,image.size.width,image.size.height);
UIButton* hellBtn = [[UIButton alloc] initWithFrame:frame];
[hellBtn setBackgroundImage:image forState:UIControlStateNormal];
[hellBtn setShowsTouchWhenHighlighted:NO];
[hellBtn addTarget:self action:#selector(goToHell) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:hellBtn];
[self.nav.navigationController.navigationItem setRightBarButtonItem:rightBarButtonItem];
[hellBtn release];
[rightBarButtonItem release];
if I replace the same code blog in any viewDidLoad of any viewController and change
[self.nav.navigationController.navigationItem setRightBarButtonItem:rightBarButtonItem];
By:
[self.navigationItem setRightBarButtonItem:rightBarButtonItem];
It works perfectly.
Any Idea Why?
Create a subclass of UIViewController for ex. UIViewControllerBase, override viewDidLoad method and inside it create your rightBarButtonItem and set it. Then make all of your controllers inherit UIViewControllerBase - simple OOP scenario.
You should not use this self.nav.navigationController since nav is a UINavigationController then dont get the .navigationController
Just use [self.navigationItem setRightBarButtonItem:rightBarButtonItem];

Does not autoresize when device is rotated after loading nibfromfile

I have the following question:
I got some code that gets called when an user logs in. The code has to call another view controller and has to show another view. To show to new view, i got the following code:
[scrollView removeFromSuperview];
Form1 *formcontroller1 = [[Form1 alloc] initWithNibName:#"Form1" bundle:[NSBundle mainBundle]];
[self.view setAutoresizesSubviews:YES];
[self.view addSubview:formcontroller1.view];
[scrollView release];
The problem is, when the other view is loaded and i rotate the device, the view of the new nib is not resizing correctly.
EDIT:
I wasn't dismissing the current viewcontroller so some properties remained. What i did is this:
[scrollView removeFromSuperview];
[self dismissModalViewControllerAnimated:YES];
Form1 *formcontroller = [[Form1 alloc] init];
[self presentModalViewController:formcontroller animated:YES];
[scrollView release];
You should check the autoresizing properties of your nib view in Interface Builder...
It should look like in the picture:
The middle arrows are dimmed, but still active. This is where autoresizing is set. You could try and set that property programmatically by assigning in your controller viewDidLoad method:
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
You should also ensure that both your view and its superviewhave the "autoresize subviews" button checked (in the first pane of the inspector in IB)
OLD ANSWER:
How is Form1 – shouldAutorotateToInterfaceOrientation: defined?
By default, this method returns YES for the UIInterfaceOrientationPortrait orientation only. If your view controller supports additional orientations, override this method and return YES for all orientations it supports.
Your implementation of this method should simply return YES or NO based on the value in the interfaceOrientation parameter. Do not attempt to get the value of the interfaceOrientation property or check the orientation value reported by the UIDevice class. Your view controller is either capable of supporting a given orientation or it is not.
E.g.:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
to support all orientations.