iOS 7中MFMailComposeViewController的状态栏变为黑色

59

我的iOS 7应用程序中有一个反馈按钮,使用MFMailComposeViewController。用户点击此按钮后,邮件组合器会打开,但状态栏会变为黑色。是否有人知道我该怎么办?

我只在iOS 7上遇到这个问题。我正在为iOS 7自定义我的应用程序。

    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:@"support@test.com",nil]];

            dispatch_async(dispatch_get_main_queue(), ^{
                [self presentModalViewController:mailController animated:YES];
}
13个回答

143
在 presentViewController 的完成块中设置 UIApplication statusBarStyle,用于您的 MFMailComposeViewController。例如:
    MFMailComposeViewController *mailVC = [[MFMailComposeViewController alloc] init];
    [self.navigationController presentViewController:mailVC animated:YES completion:^{
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
    }];

您可能还需要在Info.plist文件中添加和/或设置“View controller-based status bar appearance”为NO。

1
如果您在Info.plist中进行了更改,我认为setStatusBarStyle的位置并不重要,因为它将成为应用程序的全局设置。 - mackinra
1
在这一点上,preferredStatusBarStyle已经无用了。 - jfisk
1
@mackinra:并不完全是这样。我已经在我的plist和应用程序委托中设置了它,但MailViewComposeViewController在我的情况下将其从白色覆盖为黑色。尽管很奇怪,但这个解决方案已经修复了它。 - micnguyen
在Swift中,我使用了presentViewController(picker, animated: true, completion: {UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: false)}),其中picker是var picker = MFMailComposeViewController()。 - Darren
4
现在已经弃用了[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];,所以我不知道该怎么做。 - MobileMon
显示剩余2条评论

58
尝试将类别添加到MFMailComposeViewController 编辑:如果“基于视图控制器的状态栏外观”== YES,则此解决方案有效。
@implementation MFMailComposeViewController (IOS7_StatusBarStyle)

-(UIStatusBarStyle)preferredStatusBarStyle
{
   return UIStatusBarStyleLightContent;
}

-(UIViewController *)childViewControllerForStatusBarStyle
{
   return nil;
}

@end

这不起作用,因为视图控制器及其状态栏是由完全不同的进程(MailCompositionService)渲染的。 这只影响在外部进程加载时进行动画处理的预览视图控制器。 - Léo Natan
如果你重写MFMailComposeViewController类并实现这两个方法,它就可以工作了! - OemerA
5
这个方法很有效!我添加了完全相同的分类,childViewControllerForStatusBarStyle 很好地完成了它的工作!不过如果没有它,什么也不会发生。 - Yevhen Dubinin
3
这对我也奏效了。如果你想要让设置变成全局的,Keller的回答可以实现。但是如果不需要的话,这个方法也能达到目的。 - mackinra
2
不应该在类别中覆盖现有的方法。这会导致意外的行为。您可以在此处阅读更多信息:https://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html - NachoSoto
显示剩余5条评论

25

简洁解法。 将View controller-based status bar appearance设为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
    }
}

1
这似乎是在iOS 9上的正确答案。(嗯,在删除“public”关键字后。) - Adam Kaump
2
如果您想要一个更广泛的解决方案,可以扩展UINavigationController并覆盖preferredStatusBarStyle和childViewControllerForStatusBarStyle。这适用于MFMailComposeViewController以及通过短信和打印共享时呈现的共享表。 (我没有测试ABPeoplePickerNavigationController,因为我没有在我的应用程序中使用它。) - Jim Rhoades
太棒了,完美运作。尝试了很多不同的Swift方法,包括上面的completionHandler,但扩展绝对是最好的选择!!! - StuartM
2
在Swift 3中:扩展MFMailComposeViewController {override open var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } override open var childViewControllerForStatusBarStyle: UIViewController? { return nil }} - Barbara R

7
我成功的方法是:
  • 子类化MFMailComposeViewController
  • 按照答案6所述重写两个方法:

    -(UIStatusBarStyle)preferredStatusBarStyle;

    -(UIViewController *)childViewControllerForStatusBarStyle;

  • 按照以下方式重写viewDidLoad:

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

请注意,不要删除html标记。

根据我的经验,只需要覆盖这两个方法就足够了。 - Lukasz 'Severiaan' Grela
[line self preferredStatusBarStyle]; 这行代码是做什么的?它只是获取样式,然后什么也不做。 - Banana

7

解决方案:Swift3

将以下内容添加到您的ViewController中:

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

请将 View controller-based status bar appearance 设置为 YES,如下所示:

enter image description here

感谢 @SoftDesigner

另外一种更加简洁的解决方案,不会改变应用程序中的其他设置。在完成块中更改状态栏时呈现邮件 VC:

controller.present(mailComposeViewController, animated: true) {
            UIApplication.shared.statusBarStyle = .lightContent
        }

1
由于在iOS 9中设置UIApplication.shared.statusBarStyle已被弃用,因此使用扩展程序就可以解决问题了! - Hans Terje Bakke

5
有时状态栏样式无法正确更新。你应该使用:
 [self setNeedsStatusBarAppearanceUpdate];

如果想要手动刷新iOS状态栏样式,希望能够帮助节省一些时间。

[self presentViewController:picker animated:YES completion:^{
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
     [self setNeedsStatusBarAppearanceUpdate];
}];

2

对于我来说,最简单的 Swift 3 解决方案是:

extension MFMailComposeViewController {

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

        UIApplication.shared.statusBarStyle = .lightContent
    }
}

1

以上答案都对我没用。

我有两个问题:

  1. 黑色状态栏
  2. 标题栏上的透明层

enter image description here

解决方案

  1. 黑色状态栏 - 我移除了所有导航栏自定义

    // 在AppDelegate中注释以下行

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

  2. 透明标题栏 - 为MFMailComposeViewController设置navigationBarHidden = Yes

    composeViewController.navigationBarHidden = YES;


1
似乎初始化MFMailComposeViewController时,UIApplication.shared.statusBarStyle会更改为.default...因此,在展示之前保存状态并在展示后再次设置解决了我的问题:
    // 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
        }
    }

0
我正在iOS8上构建一个应用程序,并且在所有原生功能(如邮件组合器、相机等)中都遇到了状态栏的问题。以下步骤可以解决您的问题:
请将以下内容添加到您的plist文件中:
  <key>UIStatusBarHidden</key>
  <false/>
  <key>UIViewControllerBasedStatusBarAppearance</key>
  <false/>

如果您在Storyboard中使用添加行功能,则UIViewControllerBasedStatusBarAppearance不是一个选项。此外,当添加一行时,它会要求BOOLEAN(YES / NO)。它不能是源代码中的NO字符串,而必须是false布尔值。请改为将plist作为源代码打开并添加上述行。删除您以前的尝试。现在,您将能够成功应用在网络上找到的许多不完整答案中给出的代码片段。

您现在可以在应用程序委托文件中添加全局更改和/或在控制器本身中进行覆盖。如果没有上述内容,当使用本地函数时,我尝试过的所有堆栈溢出代码都失败了。现在一切都运行得非常完美。

作为测试,请将任何对任何内置“完成”调用的调用替换为

    completion:^{[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接