Last Updated: February 25, 2016
·
1.298K
· Andrej Mihajlov

Patching Mail controller on iOS

MFMailComposeViewController has been around for a while and is the easiest way to send email from app.

It does its job okay, it has fine user interface and it takes care about email delivery, email accounts and many other things.

However everything goes wrong, once you customize UIAppearance. It's kinda strange but this controller adopts only global style for UINavigationBar and there is no way to directly change navigation bar appearance, even though essentially it is navigation controller.

The customization options for this controller are quite limited since it has Remote View Controller under the hood running in separate process. But we still can customize navigation bar.

Screenshot

I use a screenshot from message controller which is very similar to mail controller, but breaks a bit more than mail controller.

Since it takes appearance from global UINavigationBar style, we can swap styles between showing and hiding mail controller. Timing is very important here, to avoid the rest of the app from falling apart.

The same approach can be used for MFMessageComposeViewController.

#import <MessageUI/MessageUI.h>

@interface MFMailComposeViewControllerSubclass : MFMailComposeViewController
@end

static id originalTintColor;
static id originalBarTintColor;
static id originalTitleTextAttributes;

@implementation MFMessageComposeViewControllerSubclass

- (id)init {
    [self patch];

    if(!(self = [super init])) {
        [self unpatch];
    }

    return self;
}

- (void)patch {
    id navigationBarAppearance = [UINavigationBar appearance];

    // Save original appearance
    originalTintColor = [navigationBarAppearance tintColor];
    originalBarTintColor = [navigationBarAppearance barTintColor];
    originalTitleTextAttributes = [navigationBarAppearance titleTextAttributes];

    // Reset to default appearance
    [navigationBarAppearance setTintColor:nil];
    [navigationBarAppearance setBarTintColor:nil];
    [navigationBarAppearance setTitleTextAttributes:nil];
}

- (void)unpatch {
    id navigationBarAppearance = [UINavigationBar appearance];

    [navigationBarAppearance setTintColor:originalTintColor];
    [navigationBarAppearance setBarTintColor:originalBarTintColor];
    [navigationBarAppearance setTitleTextAttributes:originalTitleTextAttributes];

    originalBarTintColor = nil;
    originalBarTintColor = nil;
    originalTitleTextAttributes = nil;
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self unpatch];
}

@end