MFMailComposeViewController in iOS 7 statusbar are black
Asked Answered
S

13

59

i have a feedback button in my ios 7 application with MFMailComposeViewController. After the user click this button the mailcomposer open but the statusbar changed to black. Have anybody a idea what can i do?

i have this problem only with ios7. i customizing my app for ios7.

    MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
            mailController.mailComposeDelegate = self;

            [mailController setSubject:@"Feedback"];
            // Fill out the email body tex
            NSString *emailBody = [NSString stringWithFormat:@"testest"],
                                   [UIDevice currentDevice].model,
                                   [UIDevice currentDevice].systemVersion];
            [mailController setMessageBody:emailBody isHTML:NO];
            [mailController setToRecipients:[NSArray arrayWithObjects:@"[email protected]",nil]];

            dispatch_async(dispatch_get_main_queue(), ^{
                [self presentModalViewController:mailController animated:YES];
}
Sister answered 22/9, 2013 at 15:19 Comment(0)
H
143

Set the UIApplication statusBarStyle in the completion block of presentViewController for your MFMailComposeViewController. i.e.

    MFMailComposeViewController *mailVC = [[MFMailComposeViewController alloc] init];
    [self.navigationController presentViewController:mailVC animated:YES completion:^{
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
    }];

You may also need to add and/or set "View controller-based status bar appearance" to NO in your Info.plist file.

Hecatomb answered 4/10, 2013 at 19:32 Comment(7)
If you make that change in your Info.plist, I don't think it matters where you do the setStatusBarStyle, as it becomes the global setting for the app.Powe
this shouldt be marked as the correct answer since preferredStatusBarStyle at this point on is uselessCommunist
@mackinra: Not exactly. I have it set on my plist and app delegate, but MailViewComposeViewController overrides it to black from white in my case. This solution has fixed it, as weird as it is.Tapestry
I had to do [self presentViewController:mailVC... instead of [self.navigationController...Caddie
In swift, I used presentViewController(picker, animated: true, completion: {UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: false)}) where picker is var picker = MFMailComposeViewController()Coxalgia
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; is deprecated now so I don't know what to doDraughtsman
Now that setStatusBarStyle is deprecated (since iOS 9 actually) what is the way to do it? Subclassing MFMailComposeViewController and overriding preferredStatusBarStyle does not work, any idea?Arcturus
S
58

Try to add category to MFMailComposeViewController

EDIT: this solution works if "View controller-based status bar appearance" == YES

@implementation MFMailComposeViewController (IOS7_StatusBarStyle)

-(UIStatusBarStyle)preferredStatusBarStyle
{
   return UIStatusBarStyleLightContent;
}

-(UIViewController *)childViewControllerForStatusBarStyle
{
   return nil;
}

@end
Slat answered 25/9, 2013 at 12:52 Comment(10)
This does not work, because the view controller, and its status bar, are rendered by a different process entirely (MailCompositionService). This only influences the preview view controller that is animated while the external process loads.Copestone
If you override MFMailComposeViewController class and implement just these two methods it works!Poitiers
This works! I have added exactly the same category and childViewControllerForStatusBarStyle does its job pretty well! Without it though nothing happens.Practically
This worked me too. Keller's answer will work if you want to make the setting global, but if you don't, this one does the trick.Powe
You shouldn't override existing methods in a category. This leads to unexpected behavior. You can read more about that here: mikeash.com/pyblog/…Agnew
If I re-call this wont' work anymore because Apple patched categories so you can't override native functions to the class.Renaldorenard
This solution still works when subclassing MFMailComposeViewController.Runnels
This worked for me. iOS 8.4, Xcode 6.4, ARC enabled. Thanks Igor, here are a few helpful topics for anyone reviewing this solution... What is a category? developer.apple.com/library/ios/documentation/General/… Review this article to learn how to add categories: https://mcmap.net/q/94686/-how-do-i-create-a-category-in-xcode-6-or-higherPassed
This works for me, running iOS 10.0 though I'm using a subclass rather than a category.Tusker
This works in iOS 11. I subclassed MFMailComposeViewController instead, to avoid global styling and implemented preferredStatusBarStyle (light content) and childViewControllerForStatusBarStyle (nil) and it works great. You must adjust info.plist as described above as well.Truckle
S
25

Swift solution. Set View controller-based status bar appearance to YES

import UIKit
import MessageUI
import AddressBookUI

extension MFMailComposeViewController {
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }

    override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return nil
    }
}

extension ABPeoplePickerNavigationController {
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }

    override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return nil
    }
}
Switchman answered 29/10, 2015 at 14:0 Comment(4)
This appears to be the correct answer with iOS 9. (Well, after removing the "public" keywords.)Lilt
If you want a broader solution, you can instead extend UINavigationController and override both preferredStatusBarStyle and childViewControllerForStatusBarStyle. That works for MFMailComposeViewController and the share sheets presented when sharing via text message and printing. (I haven't tested ABPeoplePickerNavigationController, since I'm not using that in my app.)Murrey
Great idea, works perfectly. Tried a bunch of different swift approaches including the completionHanlder above, but the extension is definitely the way to go!!!Obfuscate
In Swift 3: extension MFMailComposeViewController { override open var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } override open var childViewControllerForStatusBarStyle: UIViewController? { return nil } }Fite
S
7

What did the trick for me was:

  • Subclass MFMailComposeViewController
  • Override the two methods as described in answer 6

    -(UIStatusBarStyle)preferredStatusBarStyle;

    -(UIViewController *)childViewControllerForStatusBarStyle;

  • Override viewDidLoad as follows:

    -(void)viewDidLoad {
    [super viewDidLoad];
    [self preferredStatusBarStyle];
    [self setNeedsStatusBarAppearanceUpdate];
    }

Stanford answered 9/11, 2013 at 19:26 Comment(2)
As of my experience it was enough to override those 2 methods.Casiano
What does line [self preferredStatusBarStyle]; do? It only gets the style and then does nothing with it.Superego
G
7

Solution for Swift3

Add this to your ViewController:

extension MFMailComposeViewController {
    open override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}

Set View controller-based status bar appearance >> YES as below:

enter image description here

Thanks to @SoftDesigner

Another cleaner solution that may not change other settings in your app. While presenting the Mail VC change the status bar in the completion block:

controller.present(mailComposeViewController, animated: true) {
            UIApplication.shared.statusBarStyle = .lightContent
        }
Gatias answered 14/3, 2017 at 22:27 Comment(1)
Since setting UIApplication.shared.statusBarStyle is deprecated in iOS 9, the extension did the trick!Unblushing
W
5

Some times it will not update the status bar style properly. You should use

 [self setNeedsStatusBarAppearanceUpdate];

To say iOS to refresh the status bar style, manually. Hope someone would save some time on knowing it.

[self presentViewController:picker animated:YES completion:^{
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
     [self setNeedsStatusBarAppearanceUpdate];
}];
Wenzel answered 12/3, 2014 at 8:20 Comment(0)
G
2

The easiest swift 3 solution for me was:

extension MFMailComposeViewController {

    open override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        UIApplication.shared.statusBarStyle = .lightContent
    }
}
Gies answered 18/8, 2017 at 11:46 Comment(0)
A
1

None of above answers are work for me.

I have two issues.

  1. Black status bar
  2. transparent layer on title bar

enter image description here

Solution

  1. Black status - I remove all navigation bar customization

    // comment below line in AppDelegate

    [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"nav_bg"] forBarMetrics:UIBarMetricsDefault];

  2. Transparent title bar - set navigationBarHidden = Yes for MFMailComposeViewController

    composeViewController.navigationBarHidden = YES;

Augustus answered 31/12, 2014 at 11:40 Comment(0)
W
1

It seems that initializing the MFMailComposeViewController UIApplication.shared.statusBarStyle will change to .default... so, saving the state before and setting it again after presentation solved the problem for me:

    // save the state, otherwise it will be changed
    let sbs = UIApplication.shared.statusBarStyle

    let mailComposerVC = MailComposerVC()
    mailComposerVC.navigationBar.barTintColor = UINavigationBar.appearance().barTintColor
    mailComposerVC.navigationBar.tintColor = UINavigationBar.appearance().tintColor
    mailComposerVC.navigationBar.barStyle = UINavigationBar.appearance().barStyle

    if MFMailComposeViewController.canSendMail() {
        APP_ROOT_VC?.present(mailComposerVC, animated: true, completion: {
            // reapply the saved state
            UIApplication.shared.statusBarStyle = sbs
        })
    }

    public class MailComposerVC: MFMailComposeViewController {

        public override var preferredStatusBarStyle: UIStatusBarStyle {
            return UIApplication.shared.statusBarStyle
        }
        public override var childViewControllerForStatusBarStyle : UIViewController? {
            return nil
        }
    }
Waylan answered 15/11, 2016 at 12:11 Comment(0)
I
0

iOS 7 introduces a method prefersStatusBarHidden, but it won't be so easy to use in this case. You may prefer to use the statusBarHidden property of UIApplication while the modal is presented.

Interpose answered 22/9, 2013 at 15:25 Comment(1)
thx 4 your answer. i test it with: [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone]; the same problem :(Sister
M
0
[self presentViewController:mailViewController animated:YES completion:^(void) { [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES]; }];
Marcelmarcela answered 2/4, 2014 at 11:30 Comment(0)
L
0

In my case, I was using "view controller-based status bar appearance" and presenting a modal view controller with a custom segue transition and then presenting the MFMailComposeViewController from there. In this situation, by default, iOS only respects/uses the presenting or "root" view controller's preferredStatusBarStyle method.

So once I overrode childViewControllerForStatusBarStyle in my root view controller and preferredStatusBarStyle in my modal view controller, everything worked as expected... something like this:

// in RootViewController.m ...
- (UIViewController *)childViewControllerForStatusBarStyle {
    return self.modalViewController;
}

// in ModalViewController.m ...
- (UIStatusBarStyle)preferredStatusBarStyle {
    if (self.mailController != nil)
        return UIStatusBarStyleDefault;
    return UIStatusBarStyleLightContent;
}
Lewls answered 18/11, 2014 at 11:27 Comment(0)
A
0

I am building an application in iOS8 and have had issues with the status bar with all native functions such as the mail composer, the camera, etc.. The following will solve your issues:

Put the following in your plist file

  <key>UIStatusBarHidden</key>
  <false/>
  <key>UIViewControllerBasedStatusBarAppearance</key>
  <false/>

If you are using the add row feature in storyboard, the UIViewControllerBasedStatusBarAppearance is not an option. Also when adding a row it asks for BOOLEAN (YES/NO). It cannot be a NO string in the source code it must be a false boolean. Open the plist as source code instead and add the above rows. Remove your old attempts. You will now be able to successfully apply the code snippets given in so many incomplete answers found on the net.

You can now add global changes in the app delegate file and/or overrides in the controllers themselves. Without the above being in place all the stack overflow code I have tried has failed when using a native function. Now all is working perfectly.

As a test, replace any calls to any onboard "completion" calls with

    completion:^{[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];}
Alcheringa answered 2/1, 2015 at 7:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.