UINavigationBar 在 Modal 上的外观未设置

Posted

技术标签:

【中文标题】UINavigationBar 在 Modal 上的外观未设置【英文标题】:UINavigationBar Appearance on Modal Not Setting 【发布时间】:2014-01-14 01:40:02 【问题描述】:

我在 appDelegate 中使用以下代码来设置整个应用中 UINavigationBar 和状态栏的外观:

[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
[[UINavigationBar appearance] setTitleTextAttributes:@NSForegroundColorAttributeName: [UIColor whiteColor]];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

此代码正确地将所有内容的外观设置为白色,除非第三方模式视图控制器被阻止,例如来自 Dropbox API 或来自 UIActivityViewController 的邮件/消息视图控制器。我添加了一些屏幕截图来展示它们的外观。

UIActivityViewController 邮件:

UIActivityViewController 消息:

Dropbox API:

我试着把它放进去

[[UINavigationBar appearanceWhenContainedIn:[MFMailComposeViewController class], nil] setTitleTextAttributes:@NSForegroundColorAttributeName: [UIColor whiteColor]];

还有

[[UINavigationBar appearanceWhenContainedIn:[UIActivityViewController class], nil] setTintColor:[UIColor whiteColor]];

两个都没有工作。

【问题讨论】:

我向 Apple 寻求帮助,他们确认这是一个错误。我已经提交了一个错误报告,所以希望这将在 ios 7.1 中得到修复 我注意到 DropBox API 正在使相反的事情发生。取消是白色的,所以 setTintColor 正在工作,但 setTitleTextAttributes 没有。任何原因或您是否找到了另一种解决方案。它仍然是 iOS 7.1 中的一个错误 遗憾的是,仍然没有解决方案。我提交的错误报告也没有任何动静。我建议您提交自己的错误报告并参考我的 15959753。 我看了这个WWDC2013 video Customizing Your App’s Appearance for iOS 7 并注意到子视图和设置tintColour 存在继承问题。如果它失败了,我需要对它进行更多研究并跟进你的 BR。 【参考方案1】:

和你一样,我一直在尝试改变 UIActivityViewController 的外观,它是“子”控制器。在 iOS7 中,外观 API 似乎有些错误。 UIActivityViewController 可能是一个不同的进程,并且肯定是一个单独的窗口,所以我并不感到惊讶,因为它的样式很麻烦。

无论如何,我找到了解决这个问题的有趣方法,但您的设计师可能不喜欢它。创建 UIWindow 的子类(例如:MyWindow),将其实例化为主窗口,每次使用外观 API 时都像这样使用它:

[UINavigationBar appearanceWhenContainedIn:[MyWindow class], nil].barTintColor = [UIColor redColor];

这样,您将只为实际属于您的应用程序的视图设置样式,而 Apple 提供的视图将保持白色/蓝色。我想这不是您正在寻找的解决方案,但另一方面它可以让用户很好地了解您的应用程序是什么以及系统提供了什么;)

【讨论】:

【参考方案2】:

在 iOS 8 中,UIActivityViewController 在应用程序的根视图控制器上显示其单独的撰写控制器。

您需要子类化您的根视图控制器(无论是 UIViewController 还是 UINavigationController)并添加以下代码。

@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

然后,不要在 AppDelegate 或故事板中初始化 UINavigationController,而是初始化新的子类控制器。

其他一些建议是 UIActivityViewController 的子类,但这不起作用。

如果您还想更改栏按钮和标题颜色,请在您的应用程序中使用以下代码: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]];

【讨论】:

注意:如果rootViewController.presentedController != nil,那么UIActivityViewControllerrootViewController.presentedController上展示其VC 外观答案的第二部分对我不起作用,所以我最终得到了这个解决方案:***.com/a/35271959/2327139【参考方案3】:

我已经为这个问题苦苦挣扎了好几个小时,我的结论是UIActivityViewController 中的所有活动都可能有自己的样式实现,并且看起来取决于它。

基本问题:您可以自定义一些内容以使邮件和消息看起来正常,但其他应用程序可能看起来不对。即:Facebook Messenger 出于某种原因强制状态栏变亮。

我的建议:创建UIWindow 的子类,在您的应用程序中使用该子类并将UIAppearance 定位到该窗口类,并让系统的接口只是:),(或使用细微的变化,例如色调)。

@interface MyWindow : UIWindow

@end

// further in code
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[MyWindow class]]] setTintColor:[UIColor orangeColor]];

仅供参考:使用UIActivityViewController时,我们实际上无法控制状态栏

希望这会有所帮助。

【讨论】:

【参考方案4】:

由于目前还没有解决方案,我做了以下设置 UIActivityViewController modal 的导航栏颜色为白色(因为我的应用程序的导航栏颜色为蓝色),以便用户至少可以看到按钮:

[[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]];

当用户完成 UIActivityViewController modal 时,应用的主导航栏颜色返回为蓝色。

希望有人会发布更好的解决方案。

【讨论】:

嗯,目前这是一个很好的“解决方法”。然而,我能够让我的外观设置恢复到我的蓝色的唯一方法是使用这个:[shareView setCompletionHandler:^(NSString *activityType, BOOL completed) [[UINavigationBar appearance] setBarTintColor:NAVBARCOLOR]; [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]]; [[UINavigationBar appearance] setTitleTextAttributes:@NSForegroundColorAttributeName: [UIColor whiteColor]]; ]; 尽管实际问题没有得到解决,但我将不回答这个问题。跨度> 【参考方案5】:

我找到了更改发送取消按钮的文本颜色的解决方案。

查看我来自here的回答。

【讨论】:

【参考方案6】:

试试这个:

[[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]];

【讨论】:

【参考方案7】:

我有同样的问题,我使用 ActivityViewController 的完成处理程序委托将我的 bar Tint 颜色设置为白色:

shareViewController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) 
            [[UINavigationBar appearance] setTitleTextAttributes:@NSForegroundColorAttributeName:[UIColor whiteColor]];
        ;

然而,这在 iOS 8 上不再起作用了……他们稍微改变了完成处理程序的格式,代码被执行了,但颜色没有改变。

所以为了不浪费我所有的时间,这里是我的快速修复:

在显示共享控制器之前,我仍在用这条线更改全局颜色(带有维护注释)

[[UINavigationBar appearance] setTitleTextAttributes:@NSForegroundColorAttributeName:[UIColor darkGrayColor]]; // Note : In ViewWillAppear the color is set back to white

在每个调用 UIActivityViewController 的视图控制器中,我在 viewWillAppear 方法中设置代码以获取颜色。

- (void)viewWillAppear:(BOOL)animated

    [super viewWillAppear:animated];

    [[UINavigationBar appearance] setTitleTextAttributes:@NSForegroundColorAttributeName:[UIColor whiteColor]];

这很有效,尽管它会导致代码缺乏凝聚力。

【讨论】:

【参考方案8】:

我使用walapu's answer 来制定自己的解决方案。关键是,我也在presentViewController:animated:completion: 中设置了导航栏的色调颜色,并且没有使用外观代理,而是直接用于 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();
        
    ];

【讨论】:

【参考方案9】:

我特别遇到了 iMessage 的问题。必须设置导航栏背景图像,设置色调不起作用。使用切片以我的颜色拉伸 2x2 像素的图像。

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

【讨论】:

【参考方案10】:

在这里,我在呈现活动视图之前立即更改导航栏的全局外观,并在活动视图关闭后将其更改回来。 (在 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, ...

【讨论】:

以上是关于UINavigationBar 在 Modal 上的外观未设置的主要内容,如果未能解决你的问题,请参考以下文章

UINavigationBar 在 PushViewController 上隐藏 UIBarButtons

如何在 UINavigationBar 上设置图像

如何在 UINavigationBar 上设置自定义按钮?

如何在 UINavigationBar 上添加 UISearchBar 动画

在 UINavigationBar 上呈现 UISearchController 时推送视图控制器

在 UIStatusBar 上设置与 UINavigationBar 相同的背景颜色