I saw an article a while back, which is here:
User Interface Customization in iOS 6
It shows customization for iOS 6. Since the article I have written Apps that use the technique, it is pretty straightforward, no magic in there.
However, I need to update one of my apps and under iOS 7 it does not work correctly. It appears that customization of UIBarButtonItems does not work the first time the view is presented. If I dismiss the view and then present it agin everything works fine. What is seen is shown here:
First time view is presented:
Second time:
I have seen this issue in his example, my code and a test app I wrote. The code is as follows:
// Customizing the Back Bar Buttons
UIImage * btBack_30 = [[UIImage imageNamed:@"btBack_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)];
UIImage * btBack_24 = [[UIImage imageNamed:@"btBack_24"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 5)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:btBack_30 forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:btBack_24 forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
As you can see there is no real magic, pretty standard, but I cannot find any reason or explanation why this does not work in iOS 7. The code gets executed in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
.
I hope someone has seen this and can offer a solution. Thanks for any help!
** Note: it was proposed that this is not an apple bug, but by design. I am not saying it IS an apple issue, it could more likely be mine, but if you run either of the sample or copy and paste the code below it is apparent that the first time it does not work correctly and subsequent times it does. That would lead me to believe that the api calls are valid, but either they have a bug, or I am missing something that needs to be done.
**** UPDATE 4:**
I changed the code in MyAppDelegate's init method in my sample to the following based on the suggestion of FruityGeek, but still no luck:
- (instancetype)init
{
self = [super init];
if (self)
{
//Other UIAppearance proxy calls go here
[[UIBarButtonItem appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
//[UIColor colorWithRed:220.0/255.0 green:104.0/255.0 blue:1.0/255.0 alpha:1.0],
[UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1.0],
UITextAttributeTextColor,
//[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0],
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0.5, 0.5)],
UITextAttributeTextShadowOffset,
[UIFont systemFontOfSize:12.0],
UITextAttributeFont,
nil]
forState:UIControlStateNormal];
// Customizing the Back Bar Buttons
//ios6 uses whole button background image
UIImage * btBack_30 = [[UIImage imageNamed:@"btBack_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)];
UIImage * btBack_24 = [[UIImage imageNamed:@"btBack_24"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 5)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:btBack_30 forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:btBack_24 forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
if ([[UIDevice currentDevice].systemVersion integerValue] >= 7)
{
//ios7 needs additional chevron replacement image
UIImage * chevronReplacement = chevronReplacement = [btBack_30 imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIImage * chevronTransitionMaskReplacement = chevronTransitionMaskReplacement = [btBack_30 imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[[UINavigationBar appearance] setBackIndicatorImage:chevronReplacement];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:chevronTransitionMaskReplacement];
}
}
return self;
}
**** UPDATE 3:**
I have added a dropbox link to a sample project. This is in addition to the already posted link above which is a simple app that also shows the issue. Both can be built and run in the simulator with iOS 6 and iOS 7. In the iOS 6 case everything works as expected. In iOS 7, if you click the table cell and present the next view the custom back button is not shown, if you go back and present it again the button is there.
I have been fooling with this for days, so I hope someone else sees it and can tell me what I am missing.
https://www.dropbox.com/s/oi1bh3emvtbmms0/NavigationBarDemo.zip
This may be silly, but could it have to do with my images? I will try the sample with different images and post an update.
- Tried with different images and that makes no difference, also used images from the above posted sample. It was a long shot, but since no one seems to have a better idea yet it was worth a try.
**** UPDATE 2:**
I have tried this in another test app and moved the code to the init meted of the app delegate and it still does not work. I have this posted here as well as the original authors site of the link at the top. Plus another forum, but no one seems to have a solution.
I am wondering if this could be an Apple bug?
**** UPDATE 1:**
Moved code from didFinishLaunchingWithOptions
to willFinishLaunchingWithOptions
and init
and it still does not appear to work.
***** INIT METHOD FROM AppDelegate.m
- (id)init
{
// Create resizable images
UIImage *gradientImage44 = [[UIImage imageNamed:@"navBar_44"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
UIImage *gradientImage32 = [[UIImage imageNamed:@"navBar_32"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
// Set the background image for *all* UINavigationBars
[[UINavigationBar appearance] setBackgroundImage:gradientImage44 forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundImage:gradientImage32 forBarMetrics:UIBarMetricsLandscapePhone];
// Customize the title text for *all* UINavigationBars
[[UINavigationBar appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1.0],
UITextAttributeTextColor,
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(1, 1)],
UITextAttributeTextShadowOffset,
[UIFont boldSystemFontOfSize:18.0],
UITextAttributeFont,
nil]];
// Customizing the NavBar Buttons
UIImage * button30 = [[UIImage imageNamed:@"btButton_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)];
UIImage * button24 = [[UIImage imageNamed:@"btButton_24"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)];
[[UIBarButtonItem appearance] setBackgroundImage:button30 forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackgroundImage:button24 forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
[[UIBarButtonItem appearance] setTintColor:[UIColor whiteColor]];
[[UIBarButtonItem appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
//[UIColor colorWithRed:220.0/255.0 green:104.0/255.0 blue:1.0/255.0 alpha:1.0],
[UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1.0],
UITextAttributeTextColor,
//[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0],
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0.5, 0.5)],
UITextAttributeTextShadowOffset,
[UIFont systemFontOfSize:12.0],
UITextAttributeFont,
nil]
forState:UIControlStateNormal];
// Customizing the Back Bar Buttons
UIImage * btBack_30 = [[UIImage imageNamed:@"btBack_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)];
UIImage * btBack_24 = [[UIImage imageNamed:@"btBack_24"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 5)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:btBack_30 forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:btBack_24 forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
return [super init];
}