MailComposeViewController does not keep status bar style [duplicate] - ios

This question already has answers here:
MFMailComposeViewController in iOS 7 statusbar are black
(13 answers)
Closed 3 years ago.
I'm having an issue with the navigation Bar in MFMailComposeViewController.
I have an app where we set the "Status bar style" to "UIStatusBarStyleLightContent" in the plist file. It works perfectly in all views except when I call up MFMailComposeViewController. It goes back to black. The rest is ok. We have a custom image that does carry forward, and I can set the tint color with no problems. Any one know how to fix this? How to reset the "Status bar style" to "UIStatusBarStyleLightContent" in mail?
in AppDelegate
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"headerLogo.png"] forBarMetrics:UIBarMetricsDefault];
calling mail
MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
mailController.mailComposeDelegate = self;
[[mailController navigationBar] setTintColor:[UIColor whiteColor]];
[[mailController navigationBar] setBarTintColor:[UIColor whiteColor]];
[self presentViewController:mailController animated:YES completion:nil];

I believe setting the barStyle in MFMailViewController is something that is not accessible unless because of private API in Apple's code. The reason why you're able to set the UINavigationBar to a certain picture in the app delegate is because in the app delegate, you are calling to the appearance of the UINavigationBar class instead of the tint color of the MFMailViewController's navigation bar.
Hope this helps

In the info.plist add new row:
UIViewControllerBasedStatusBarAppearance
Set it to:
NO
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
[self presentViewController: mail animated: YES completion: ^ {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}];

Related

Graphic issue presenting MFMessageComposeViewController

I've this strange issue when i'm presenting a MFMessageComposeViewController in my app!
I don't know what this black bar is and i'm unable to remove the app logo from the NavigationBar.
And here is the code for presenting the controller
MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init];
[[messageController navigationBar] setBarTintColor:SMAN_ORANGE_COLOR];
[[messageController navigationBar] setTintColor:[UIColor whiteColor]];
messageController.messageComposeDelegate = self;
[messageController setRecipients:recipents];
[messageController setBody:message];
// Present message view controller on screen
[self presentViewController:messageController animated:YES completion:nil];
To remove the app logo, try to add in your method above the following code:
messageController.navigationItem.titleView = [UIImageView new];
To change the Status Bar style (White Color) add the following code before presenting the messageController:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
Also in your .plist file set:
View controller-based status bar appearance to NO
I solve the issue subclassing my UINavigationController and changing the appearance of it with [UINavigationBar appearanceWhenContainedIn:[myNavControllerSubclass class], nil]
[self presentViewController:messageController animated:YES completion:^{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:NO];
}];
this works in ios 8 for the white status bar
Refer answer #1 also.
As per Apple's documentation you can only present it modally.
[self presentModalViewController:messageController animated:YES];

iMessages change text color

My app is showing iMessages ViewController via UIActivityController. However, the colors of labels are all messed up (blue so they are barely visible). I think this is because the view controller is using my app's tint color. See below.
How can i fix this?
thanks!
I ran into something similar with presenting MFMailComposerViewController modally. Try setting the appearance of your app's tint color to nil when presenting the activity controller, and then back to your desired app tint when it completes. Here's what I did with MFMailComposer. You should be able to modify for your activity controller:
...
[[UINavigationBar appearance] setBarTintColor:nil]; // Set to default before presenting
MFMailComposeViewController *mailVC = [[MFMailComposeViewController alloc] init];
mailVC.mailComposeDelegate = self;
[self.navigationController presentViewController:mailVC animated:YES completion:nil];
...
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
[[UINavigationBar appearance] setBarTintColor:MyAppsCustomColor]; // set it back when finished
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
EDIT
When I use this solution, it changes the nav bar appearance in the presented modal that is selected in the activity view controller (messages, mail, etc). I'm setting my app's nav bar appearance to blue in my delegate, and then back to blue in the completion block. The app's nav bar remains blue, and the presented messages/mail modal is shown with the default light gray nav bar.
UIActivityViewController* avc =
[[UIActivityViewController alloc] initWithActivityItems:#[#""]
applicationActivities:nil];
avc.completionHandler = ^(NSString *activityType, BOOL completed) {
// ...
dispatch_async(dispatch_get_main_queue(), ^{
// Set tint color back to blue.
// This block is executed whether the user finishes or cancels.
[[UINavigationBar appearance] setBarTintColor:[UIColor blueColor]];
[[self navigationController] setNeedsStatusBarAppearanceUpdate];
});
};
[[UINavigationBar appearance] setBarTintColor:nil];
[self presentViewController:avc animated:YES completion:nil];

How do you change the colors in the Send Message dialog triggered by UIActivityViewController?

I am using the UIActivityViewController to allow the user to send messages in my app. The issue is that when I choose Message as my share method, the "To:" section inherits the background color of my NavigationBar.
This is only a problem when you choose Message as your method - if you choose Mail, everything below the NavigationBar shows up with a white background.
Here is a screenshot of my issue:
In my AppDelegate.m I have the following code in didFinishLaunchingWithOptions:
[UINavigationBar appearance].barTintColor = [RMTheme theme].accentLight;
[UINavigationBar appearance].tintColor = [UIColor whiteColor];
And the activity controller is triggered with the following code:
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:nil];
Well, I believe you are using "PUSH" style when you show your UIActivityViewController, instead you should use "Modal" style.
Storyboard
Code
[yournavigationController presentModalViewController:YourActivityViewController animated:YES];
Solution 2 - Use image
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"top_bar3"] forBarMetrics:UIBarMetricsDefault];
Solution 3 - Set bar tint
[[self navigationController]navigationBar].barTintColor = [UIColor whiteColor];

UINavigationBar Appearance on Modal Not Setting

I am using the following code in my appDelegate to set the appearance of my UINavigationBar and status bar throughout my app:
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
[[UINavigationBar appearance] setTitleTextAttributes:#{NSForegroundColorAttributeName: [UIColor whiteColor]}];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
This code correctly sets the appearance of everything to white everywhere except when a third-party modal viewController is prevented, such as from the Dropbox API or the Mail/Message viewController from a UIActivityViewController. I've included some screenshots to show how these are looking.
UIActivityViewController Mail:
UIActivityViewController Message:
Dropbox API:
I tried putting this in
[[UINavigationBar appearanceWhenContainedIn:[MFMailComposeViewController class], nil] setTitleTextAttributes:#{NSForegroundColorAttributeName: [UIColor whiteColor]}];
as well as
[[UINavigationBar appearanceWhenContainedIn:[UIActivityViewController class], nil] setTintColor:[UIColor whiteColor]];
and neither one is working.
Like you, I've been trying to alter the appearance of UIActivityViewController and it's "sub" controllers. It seems that in iOS7 the appearance API is somewhat buggy. UIActivityViewController is probably a different process and for sure a separate window, so I'm not really surprised that it's troublesome to style it.
Anyway I found an interesting way around this issue, but your designers might not like it. Create a subclass of UIWindow (ex: MyWindow), instantiate it as your main window and every time you use appearance API use it like this:
[UINavigationBar appearanceWhenContainedIn:[MyWindow class], nil].barTintColor = [UIColor redColor];
This way you'll only style views that actually belong to your application and the Apple-provided views will remain white/blue. I guess it's not the solution you were looking for, but on the other hand it gives users a good understanding what is your app and what is system-provided ;)
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've been struggling with this same issue for hours and my conclusion is that all activities from the UIActivityViewController may have their own style implementation and will look depending on that.
Basic problem: You can customise something to look ok for mail and messages, but other apps may look wrong. i.e: Facebook Messanger for some reason forces status bar to be light.
My recommendation: Create a subclass of UIWindow, use that subclass within your application and target UIAppearance to that window class and let the system's interfaces to just be :), (or with minor changes like tint color).
#interface MyWindow : UIWindow
#end
// further in code
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:#[[MyWindow class]]] setTintColor:[UIColor orangeColor]];
FYI: We have literally no control over status bar when using UIActivityViewController
Hope this helps.
Since there is no solution until now, I did the following to set the color of navigation bar of UIActivityViewController modal to white (as my app's navigation bar color is blue) so that the users can at least see the buttons:
[[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]];
When the user is done with the UIActivityViewController modal, the app's main navigation bar color is returned to blue.
Hopefully somebody will post a better solution.
I found a solution to change the text color of the Send and Cancel buttons.
Check my answer from here.
Try this:
[[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]];
I have the same problem and I used ActivityViewController's completion handler delegate to set back my bar Tint color to white with this line :
shareViewController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
[[UINavigationBar appearance] setTitleTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor]}];
};
However this doesn't work anymore on iOS 8... They changed little bit the completion handler format, the code got executed but the color didn't change.
So in order not to waste all of my time here is my quick fix :
I am still changing the global color with this line just before showing the sharing controller (with comment for maintenance)
[[UINavigationBar appearance] setTitleTextAttributes:#{NSForegroundColorAttributeName:[UIColor darkGrayColor]}]; // Note : In ViewWillAppear the color is set back to white
In each view controller that are calling a UIActivityViewController, I am setting in the viewWillAppear method the code to get the color back.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[UINavigationBar appearance] setTitleTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor]}];
}
This works good although it produce lack of cohesion in the code.
I used walapu's answer to make my own solution. The point is, that I set up navigation bar tint color also in presentViewController:animated:completion: and not using appearance proxy, but directly for MFMailComposeViewController.
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)animated completion:(void (^)(void))completion
{
if ([viewControllerToPresent isKindOfClass:[MFMailComposeViewController class]]) {
[((MFMailComposeViewController *)viewControllerToPresent).navigationBar setTintColor:[UIColor whiteColor]];
}
[super presentViewController:viewControllerToPresent animated:animated completion:^{
if ([viewControllerToPresent isKindOfClass:[MFMailComposeViewController class]]) {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
if (completion) {
completion();
}
}];
}
I had a problem in particular with iMessage. Had to set navbar background image, setting the tint didn't work. Used slicing to stretch a 2x2 pixel image with my color.
[UINavigationBar.appearance setBackgroundImage:[UIImage imageNamed:#"red"]
forBarMetrics:UIBarMetricsDefault];
Here I change the nav bar's global appearance immediately before presenting the activity view, and change it back once the activity view is dismissed. (Tested on iOS 12, Swift 5)
let activityVC = UIActivityViewController...
// Temporarily change the nav bar button's tint color.
let originalColor = UINavigationBar.appearance().tintColor
activityVC.completionWithItemsHandler = { type, completed, items, error in
UINavigationBar.appearance().tintColor = originalColor
}
UINavigationBar.appearance().tintColor = UIColor.blue
present(activityVC, ...

UIAppearance Remove Custom NavBar Background for MFMailComposeViewController

I have a custom navBar image in the navigation controllers in my app, set using UIAppearance protocol. However, when sending mail through the app (via MFMailComposeViewController), I want the default navBar instead of the custom one. I tried the approach outlined in this question: UIAppearance Remove Custom NavBar Background for UIPopoverController but it did not work. The code I used was:
[[UINavigationBar appearanceWhenContainedIn:[MFMailComposeViewController class], nil] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
But it had no effect whatsoever. My app is iOS 6+. Is this something specific to MFMailComposeViewController or am I missing something from this?
Edit: other approaches attempted:
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
mailer.navigationBar.barStyle = UIBarStyleBlack;
[self.navigationController presentViewController:mailer animated:YES completion:nil];
[mailer.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
Setting UIBarStyleBlack has some effect as the "Cancel" button subsequently turns black, but the background image is still set at the old value.
Try something like this:
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
[mail.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
This should reset the background image for just this instance.
Remove custom background image
[[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
BEFORE calling,
MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
Point is to set any customization for Navigation Bar appearance before init.

Resources