模态视图中的UINavigationBar外观未设置

10

我正在使用下面的代码在我的appDelegate中设置UINavigationBar和状态栏的外观:

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

这段代码可以将所有东西的外观设置为白色,除非有第三方模态viewController被阻止,比如来自Dropbox API或UIActivityViewController的Mail/Message viewController。 我包含了一些截图以展示它们的外观。

UIActivityViewController Mail: UIActivityViewController Mail

UIActivityViewController Message: UIActivityViewController Message

Dropbox API: Dropbox API

我尝试将这段代码加入其中。

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

以及

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

而且两个都不起作用。


我向苹果寻求帮助,并得到确认这是一个漏洞。我已经提交了一个漏洞报告,希望在iOS 7.1中能够修复此问题。 - Nick
我注意到DropBox API正在发生相反的情况。取消是白色的,所以setTintColor有效,但setTitleTextAttributes无效。有什么原因或者你找到了另一个解决方案吗?这在iOS 7.1中仍然是一个错误。 - Jim
很遗憾,仍然没有解决方案。我提交的错误报告也没有任何进展。我建议您提交自己的错误报告,并引用我的编号15959753。 - Nick
我观看了这个WWDC2013视频:为iOS 7自定义应用程序外观,发现子视图和设置tintColour存在继承问题。如果失败的话,我需要进行更多的研究并跟进您的BR。 - Jim
10个回答

3

和您一样,我一直在尝试修改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或storyboard中初始化UINavigationController,而是初始化您新子类化的控制器。

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

如果您还想更改工具栏按钮和标题颜色,请在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]];

请注意:如果 rootViewController.presentedController != nil,那么 UIActivityViewController 会在 rootViewController.presentedController 上呈现其视图控制器。 - kambala
答案的第二部分在外观上对我没有用,所以我最终采用了这个解决方案:https://dev59.com/rGEi5IYBdhLWcg3wndZw#35271959 - vahotm

2

我一直在为这个问题苦苦挣扎,我的结论是UIActivityViewController中的所有活动都可能有自己的样式实现,并且会根据此而不同。

基本问题:您可以自定义某些内容以适合邮件和消息,但其他应用程序可能会出现错误。例如:Facebook Messenger由于某种原因强制状态栏为亮色。

我的建议:创建UIWindow的子类,在应用程序中使用该子类,并将UIAppearance定位到该窗口类,让系统接口只是 :),(或带有轻微的更改,如色调颜色)。

@interface MyWindow : UIWindow

@end

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

提示:当使用UIActivityViewController时,我们实际上无法控制状态栏。

希望这可以帮到您。


1
我找到了一种方法来改变“发送”和“取消”按钮的文本颜色。
请查看此处的答案。

1

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

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

当用户完成UIActivityViewController模态操作后,应用程序的主导航栏颜色将恢复为蓝色。
希望有人能发布更好的解决方案。

1
嗯,暂时来说这是一个不错的“解决方法”。然而,我能够让我的外观设置回到蓝色的唯一方法是使用以下代码: [shareView setCompletionHandler:^(NSString *activityType, BOOL completed) { [[UINavigationBar appearance] setBarTintColor:NAVBARCOLOR]; [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]]; [[UINavigationBar appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor whiteColor]}]; }]; 不过,我将保持此问题未解决。 - Nick

0
我使用walapu的答案来制作自己的解决方案。关键是,我在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();
        }
    }];
}

0

我在使用iMessage时遇到了问题。我需要设置导航栏背景图片,但是设置色调无效。我使用切片来拉伸一个2x2像素的图片,并填充上我的颜色。

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

0

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

0

我有同样的问题,我使用ActivityViewController的完成处理程序委托来将我的工具栏色调设置回白色,代码如下:

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]}];
}

这个代码虽然可以工作得很好,但它产生了代码内聚性的缺乏。


0

试试这个:

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

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