Navigationbar coloring in ViewWillAppear happens too late in iOS 10 - ios10

I am facing a weird bug, that happens only on iOS 10.
I have a application with several screens, and each screen colors the navigationBar in viewWillAppear. So when you go to the next screen, it will be properly colored.
However, when testing on iOS 10 I suddenly see the following behaviour when going back to a previous screen:
When the previous screen appears the navigationBar still has the color of the previous screen and then flashes to the proper color.
It almost looks like viewWillAppear somehow behaves as viewDidAppear.
Relevant code:
ViewController:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[ViewControllerPainter paint:self withBackground:[UIColor whiteColor] andForeground:[UIColor blackColor] andIsLight:true];
}
Painter:
+ (void)paint:(UIViewController *)controller withBackground:(UIColor *)backgroundColor andForeground:(UIColor *)foregroundColor andIsLight:(bool)isLight
{
controller.navigationController.navigationBar.opaque = true;
controller.navigationController.navigationBar.translucent = false;
controller.navigationController.navigationBar.tintColor = foregroundColor;
controller.navigationController.navigationBar.barTintColor = backgroundColor;
controller.navigationController.navigationBar.backgroundColor = backgroundColor;
controller.navigationController.navigationBar.barStyle = isLight ? UIBarStyleDefault : UIBarStyleBlack;
controller.navigationController.navigationBar.titleTextAttributes = #{NSForegroundColorAttributeName: foregroundColor};
}
Is this a bug? Is there something I can do about to fix this? It's very frustrating.

Here's what changed according to the iOS 10 SDK Release Notes:
In iOS 10, UIKit has updated and unified background management for UINavigationBar, UITabBar, and UIToolbar. In particular, changes to background properties of these views (such as background or shadow images, or setting the bar style) may kick off a layout pass for the bar to resolve the new background appearance.
In particular, this means that attempts to change the background appearance of these bars inside of -[UIView layoutSubviews], -[UIView updateConstraints], -[UIViewController willLayoutSubviews], -[UIViewController didLayoutSubviews], - [UIViewController updateViewConstraints], or any other method that is called in response to layout may result in a layout loop.
So the problem seems to be that viewWillAppear is triggering the mentioned layout loop, since it's called as a result of a layout change:
The quick fix for me was overriding popViewControllerAnimated and pushViewController and updating the navigationBar background on my subclass of UINavigationController. Here's how it looks like:
override func popViewControllerAnimated(animated: Bool) -> UIViewController? {
let poppedViewController = super.popViewControllerAnimated(animated)
// Updates the navigation bar appearance
updateAppearanceForViewController(nextViewController)
return poppedViewController
}
override func pushViewController(viewController: UIViewController, animated: Bool) {
super.pushViewController(viewController, animated: animated)
// Updates the navigation bar appearance
updateAppearanceForViewController(viewController)
}
My guess is that it works because popViewControllerAnimated and pushViewController are not called by the OS as a result of a layout change, but by a touch event. So keep that in mind if you want to find another place to update your navigationBar background.

I had to fix this with:
self.navigationController.navigationBarHidden = YES;
self.navigationController.navigationBarHidden = NO;
This way you don't have to override popviewcontroller or pushviewcontroller. It's basically triggering the navigationbar to redraw.
It's still annoying how they can just push out a new version of OS that breaks something this significant.

Try using willMoveToParentViewController, gives the same effect as overriding UINavigationController methods but without the hassle.

I am posting the solution for Objective-C (subclass of UINavigationController):
#import "FUINavigationController.h"
#interface FUINavigationController ()
#end
#implementation FUINavigationController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"current: %#",[self.topViewController class]);
if ([NSStringFromClass([self.topViewController class]) isEqualToString:#"LoginVC"]) {
[self setNavBarHidden];
}
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIViewController*)popViewControllerAnimated:(BOOL)animated {
UIViewController *popedVC = [super popViewControllerAnimated:animated];
if ([NSStringFromClass([popedVC class]) isEqualToString:#"SignUpVC"] && [NSStringFromClass([[super topViewController] class]) isEqualToString:#"LoginVC"]) {
[self setNavBarHidden];
}
return popedVC;
}
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[super pushViewController:viewController animated:animated];
[self setNavBarVisible];
}
-(void)setNavBarHidden {
[self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setShadowImage:[UIImage new]];
[self.navigationBar setTranslucent:YES];
[self.navigationBar setBackgroundColor:[UIColor clearColor]];
}
-(void)setNavBarVisible {
[self.navigationBar setBackgroundColor:[UIColor grayColor]];
[self.navigationBar setBarTintColor:[UIColor grayColor]];
[self.navigationBar setTintColor:[UIColor whiteColor]];
[self.navigationBar setTranslucent:NO];
[self.navigationBar setTitleTextAttributes:#{NSForegroundColorAttributeName :[UIColor whiteColor]}];
[self.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor whiteColor], NSForegroundColorAttributeName, [UIFont fontWithName:#"Roboto-Reqular" size:18], NSFontAttributeName,nil]];
[self.navigationBar.topItem setBackBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil]];
}
#end
OR using method swizzling:
#import <objc/runtime.h>
#import "UINavigationController+FadeOutNavigationBar.h"
#implementation UINavigationController (FadeOutNavigationBar)
+(void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
//Swizzling view will appear
SEL originalSelectorVWA = #selector(viewWillAppear:);
SEL swizzledSelectorVWA = #selector(swizzled_viewWillAppear:);
Method originalMethodVWA = class_getInstanceMethod(class, originalSelectorVWA);
Method swizzledMethodVWA = class_getInstanceMethod(class, swizzledSelectorVWA);
BOOL didAddMethodVWA =
class_addMethod(class,
originalSelectorVWA,
method_getImplementation(swizzledMethodVWA),
method_getTypeEncoding(swizzledMethodVWA));
if (didAddMethodVWA) {
class_replaceMethod(class,
swizzledSelectorVWA,
method_getImplementation(originalMethodVWA),
method_getTypeEncoding(originalMethodVWA));
} else {
method_exchangeImplementations(originalMethodVWA, swizzledMethodVWA);
}
//Swizzling popViewControllerAnimated
SEL originalSelectorPVCA = #selector(popViewControllerAnimated:);
SEL swizzledSelectorPVCA = #selector(swizzled_popViewControllerAnimated:);
Method originalMethodPVCA = class_getInstanceMethod(class, originalSelectorPVCA);
Method swizzledMethodPVCA = class_getInstanceMethod(class, swizzledSelectorPVCA);
BOOL didAddMethodPVCA =
class_addMethod(class,
originalSelectorPVCA,
method_getImplementation(swizzledMethodPVCA),
method_getTypeEncoding(swizzledMethodPVCA));
if (didAddMethodPVCA) {
class_replaceMethod(class,
swizzledSelectorVWA,
method_getImplementation(originalMethodPVCA),
method_getTypeEncoding(originalMethodPVCA));
} else {
method_exchangeImplementations(originalMethodPVCA, swizzledMethodPVCA);
}
//Swizzling pushViewController
SEL originalSelectorPVC = #selector(pushViewController:animated:);
SEL swizzledSelectorPVC = #selector(swizzled_pushViewController:animated:);
Method originalMethodPVC = class_getInstanceMethod(class, originalSelectorPVC);
Method swizzledMethodPVC = class_getInstanceMethod(class, swizzledSelectorPVC);
BOOL didAddMethodPVC =
class_addMethod(class,
originalSelectorPVC,
method_getImplementation(swizzledMethodPVC),
method_getTypeEncoding(swizzledMethodPVC));
if (didAddMethodPVC) {
class_replaceMethod(class,
swizzledSelectorPVC,
method_getImplementation(originalMethodPVC),
method_getTypeEncoding(originalMethodPVC));
} else {
method_exchangeImplementations(originalMethodPVC, swizzledMethodPVC);
}
});
}
#pragma mark - Method Swizzling
- (void)swizzled_viewWillAppear:(BOOL)animated {
[self swizzled_viewWillAppear:animated];
NSLog(#"current: %#",[self.topViewController class]);
if ([NSStringFromClass([self.topViewController class]) isEqualToString:#"LoginVC"]) {
[self setNavBarHidden];
}
}
-(void)setNavBarHidden {
[self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setShadowImage:[UIImage new]];
[self.navigationBar setTranslucent:YES];
[self.navigationBar setBackgroundColor:[UIColor clearColor]];
}
-(void)setNavBarVisible {
[self.navigationBar setBackgroundColor:[UIColor grayColor]];
[self.navigationBar setBarTintColor:[UIColor grayColor]];
[self.navigationBar setTintColor:[UIColor whiteColor]];
[self.navigationBar setTranslucent:NO];
[self.navigationBar setTitleTextAttributes:#{NSForegroundColorAttributeName :[UIColor whiteColor]}];
[self.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor whiteColor], NSForegroundColorAttributeName, [UIFont fontWithName:#"Roboto-Reqular" size:18], NSFontAttributeName,nil]];
[self.navigationBar.topItem setBackBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil]];
}
-(UIViewController*)swizzled_popViewControllerAnimated:(BOOL)animated {
UIViewController *popedVC = [self swizzled_popViewControllerAnimated:animated];
if ([NSStringFromClass([popedVC class]) isEqualToString:#"SignUpVC"] && [NSStringFromClass([[self topViewController] class]) isEqualToString:#"LoginVC"]) {
[self setNavBarHidden];
}
return popedVC;
}
-(void)swizzled_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[self swizzled_pushViewController:viewController animated:animated];
[self setNavBarVisible];
}
#end

Related

how to customize QLPreviewController's navBar and toolbar tintColor

QLPreviewController * preview = [[QLPreviewController alloc] init];
preview.dataSource = self;
preview.currentPreviewItemIndex = sender.tag;
preview.editing= YES;
[self presentModalViewController:preview animated:YES];
[preview release];
These two lines does not work for me. so be careful before writing these lines.
[preview.tabBarController.tabBar setTintColor:[UIColor blackColor]];
[preview navigationController].navigationBar setTintColor: [UIColor blackColor]];
Since iOS5 you can theme controls based on instance, globally or when contained by specific container classes. Since iOS6 the former method of subclassing QLPreviewController to set the tintColor of the UINavigationBar stopped working.
Consider one of the following as an example of a workaround that is compatible with iOS5 and iOS6:
Any UINavigationBar contained within a QLPreviewController:
[[UINavigationBar appearanceWhenContainedIn:[QLPreviewController class], nil]
setTintColor:[UIColor blackColor]];
or globally set the tintColor of all UINavigationBar instances within your app with:
[[UINavigationBar appearance] setTintColor:[UIColor blackColor]];
This same strategy works with the UITabBarController.
set style of UINavigationController with this line..
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
and for change the color of TabBar just Add the below code in viewWillAppear of your class
CGRect frame = CGRectMake(0.0, 0.0, self.view.bounds.size.width, 48);
UIView *v = [[UIView alloc] initWithFrame:frame];
[v setBackgroundColor:[UIColor colorWithRed:0.1 green:0.2 blue:0.6 alpha:0.8]];
[v setAlpha:0.5];
[[self.tabBarController tabBar] insertSubview:v atIndex:0];
[v release];
If you want to change the tintColor of the navigationBar you can push your QLPreviewController instead present it modally:
//i assume that you already have a navigationController
[[self navigationController] pushViewController:previewer animated:YES];
[self.navigationController.navigationBar setTintColor:[UIColor blackColor]];
For the bottom bar i think that is a UIToolbar not a UITabBar, probably you cant change the color (i dont know), but surely you can't call preview.tabBarController.tabBar.
I found a solution , though it is not the correct way but it works:
Make subclass of QLPreviewController
MyQLPreviewController.h
#interface MyQLPreviewController : QLPreviewController
#end
and in .m of that new subclass, copy the following code
#implementation MyQLPreviewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIToolbar *toolbar = [self getToolBarFromView:self.view]; //NOTE: Not the correct apperoach! could not think better solution, as iOS does not allow to access the toolbar properties in QLPreviewController
toolbar.barTintColor = [UIColor redColor];
}
- (UIToolbar *)getToolBarFromView:(UIView *)view
{
for (UIView *subView in view.subviews)
{
if ([subView isKindOfClass:[UIToolbar class]])
{
return (UIToolbar *)subView;
}
else
{
UIToolbar *toolBar = [self getToolBarFromView:subView];
if (toolBar)
{
return toolBar;
}
}
}
return nil;
}

How To Change Tab bar color in Xcode

How do I go about changing the tab bar color in this code? My tab bar is black. On click changes it to blue. I want to change the tow color to any other color.
This code is from :application.m
and there :rotatingTabBarController.m ,rotatingTabBarController.h
// 1B) If this app uses tabs, create a tabbed navigation application and set the default screen for each tab
// to the defaultScreenGuid in the tabs data
if([self.tabs count] > 0){
[BT_debugger showIt:self:[NSString stringWithFormat:#"building a tabbed based navigation app%#", #""]];
if([self.screens count] > 0){
//appDelegate
qoqb_appDelegate *appDelegate = (qoqb_appDelegate *)[[UIApplication sharedApplication] delegate];
//initialize the tab bar controller
rootTabBarController = [[BT_rotatingTabBarController alloc] init];
[rootTabBarController.view setFrame:[[UIScreen mainScreen] bounds]];
[rootTabBarController setDelegate:appDelegate];
rootTabBarController.view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
//if we have a tabbar color setup in the theme
if(self.rootTheme != nil){
if([self.rootTheme.jsonVars objectForKey:#"tabBarColor"]){
if([[self.rootTheme.jsonVars objectForKey:#"tabBarColor"] length] > 3){
UIColor *tabberColor = [BT_color getColorFromHexString:[self.rootTheme.jsonVars objectForKey:#"tabBarColor"]];
NSString *tabberOpacity = #".50";
if([self.rootTheme.jsonVars objectForKey:#"tabBarColorOpacity"]){
if([[self.rootTheme.jsonVars objectForKey:#"tabBarColorOpacity"] length] > 0){
tabberOpacity = [NSString stringWithFormat:#".%#", [self.rootTheme.jsonVars objectForKey:#"tabBarColorOpacity"]];
if([tabberOpacity isEqualToString:#".100"]) tabberOpacity = #".50";
}
//colorize the tab-bar
[rootTabBarController addTabColor:tabberColor:[tabberOpacity doubleValue]];
}
}
}
}
//Fill a temporary array of view controllers to assign to tab bar controller
NSMutableArray *tmpViewControllers = [[NSMutableArray alloc] init];
//loop through each tab bar item in application data
for(int i = 0; i < [[self tabs] count]; i++){
//this tab
BT_item *thisTab = (BT_item *)[[self tabs] objectAtIndex:i];
NSString *textLabel = [[thisTab jsonVars] objectForKey:#"textLabel"];
UIImage *tabIcon = [UIImage imageNamed:[[thisTab jsonVars] objectForKey:#"iconName"]];
//get the screen from the apps array of screens for this tab's view controller
if([[thisTab jsonVars] objectForKey:#"homeScreenItemId"]){
BT_item *thisTabsDefaultScreenData = [self getScreenDataByItemId:[[thisTab jsonVars] objectForKey:#"homeScreenItemId"]];
//if this is the first tab in the list, remember it as the "currently loaded screen", also make it the "previously loaded screen"
if(i == 0){
[self setCurrentScreenData:thisTabsDefaultScreenData];
[self setPreviousScreenData:thisTabsDefaultScreenData];
[thisTabsDefaultScreenData setIsHomeScreen:TRUE];
//if theScreen has an audio file..load it in the delegate
if([[BT_strings getJsonPropertyValue:thisTabsDefaultScreenData.jsonVars:#"audioFileName":#""] length] > 3){
//appDelegate
qoqb_appDelegate *appDelegate = (qoqb_appDelegate *)[[UIApplication sharedApplication] delegate];
//initialize audio in different thread to prevent UI blocking
[NSThread detachNewThreadSelector: #selector(loadAudioForScreen:) toTarget:appDelegate withObject:thisTabsDefaultScreenData];
}
}
tabBar.tintColor = [UIColor greenColor];
will crash if your IOS version is not IOS 5 see the docs
a safer approach is:
if ([tabBarController.tabBar respondsToSelector:#selector(setTintColor:)]) {
[tabBarController.tabBar setTintColor:color];
}
//NEW CODE
if ([rootTabBarController.tabBar respondsToSelector:#selector(setTintColor:)]) {
[rootTabBarController.tabBar setTintColor:tabberColor];
}
In the AppDelegate.m inside at: application didFinishLaunchingWithOptions:
Using this coding:
// use this for highlighted color
[[UITabBar appearance] setSelectedImageTintColor:[UIColor colorWithRed:(256/256.0) green:(0/256.0) blue:(0/256.0) alpha:(1.0)]];
// Use this to channge the tint colo of the entere TabBar
[[UITabBar appearance] setTintColor:[UIColor colorWithRed:(255/256.0) green:(0/256.0) blue:(0/256.0) alpha:(1.0)]];
// This change only a background color
[[UITabBar appearance] setBackgroundColor:[UIColor colorWithRed:(255/256.0) green:(255/256.0) blue:(255/256.0) alpha:1.0]];
// This for change IMG or color tint on back of highlighted button.
[[UITabBar appearance] setSelectionIndicatorImage:[UIImage imageNamed:#"YourIMG.png"]];
That's it that's all ;)
tabBar.tintColor = [UIColor greenColor];
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.tabBarController.tabBar.tintColor=[UIColor redColor];
return YES;
}
In AppDelegate.m
In IOS7 this is done differently:
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
You can follow these steps:
I created a new UINavigationController for example UIDemoNavController resulting in:
- (void)viewDidLoad{
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
[super viewDidLoad];
}
This is the full demo class:
#import "UIDemoNavController.h"
#interface UIDemoNavController()
#end
#implementation UIDemoNavController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {}
return self;
}
- (void)viewDidLoad{
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
#end

'UITabBarItem' may not respond to 'SetAction'

I have a number of tabs in my app. The tabs are working with no issues, but I'm getting some warning messages (in the title above) which I would like to get rid of. My code is as follows:
-(void)pressItem1:(id)sender {
[self presentModalViewController:settingsViewController animated:YES];
}
-(void)pressItem2:(id)sender {
[self presentModalViewController:infoViewController animated:YES];
}
-(void)pressItem3:(id)sender {
[self presentModalViewController:aboutViewController animated:YES];
}
-(void)viewDidLoad {
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"background.png"]];
CGRect frame = CGRectMake(0, 0, 480, 49);
UIView *v = [[UIView alloc] initWithFrame:frame];
UIImage *i = [UIImage imageNamed:#"smallMenuBackground.png"];
UIColor *c = [[UIColor alloc] initWithPatternImage:i];
v.backgroundColor = c;
[c release];
[mainTabBar insertSubview:v atIndex:0];
[v release];
[settingsBarItem setAction:#selector(pressItem1:)];
[infoBarItem setAction:#selector(pressItem2:)];
[aboutBarItem setAction:#selector(pressItem3:)];
//initialSyncSwitch = NO;
[super viewDidLoad];
}
The tabs are working, but there is probably a better way of doing it so I don't get these warnings.
Regards,
Stephen
You don't set actions directly on a UITabBarItem. Instead, you should be implementing the UITabBarDelegate in the UIViewController that creates it. Specifically, the delegate should implement:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
In here, you can call pressItem1, pressItem2, etc based on which item is passed.

How to change orientation of main windows and other views navigated by window dynamically?

I have a code in which all UI items created by dynamically. I have a navigation controller which connect to other view to main window. In this I have a problem that when I write a code for orientation change then it not work automatically.
pragma mark MainViewController
#implementation MainViewController
#synthesize imageView;
#synthesize btnBegin, btnSite;
#synthesize phoneNumber;
- (void)viewDidLoad { self.title=#"Midwest Sleep Test";self.view.backgroundColor = [UIColor whiteColor];
CGRect myImageRect = CGRectMake(-10,-10,320,313);
imageView = [[UIImageView alloc] initWithFrame:myImageRect];
[imageView setImage:[UIImage imageNamed:#"midwestsleep.png"]];
[self.view addSubview:imageView];
[imageView release];
btnBegin = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnBegin addTarget:self action:#selector(Begin:) forControlEvents:UIControlEventTouchUpInside];
[btnBegin setTitle:#"Begin!" forState:UIControlStateNormal];
btnBegin.frame = CGRectMake(112,295,95,45);
[self.view addSubview:btnBegin];
CGRect myLabelRect = CGRectMake(112,345,130,22);
phoneNumber=[[UILabel alloc] initWithFrame:myLabelRect];
phoneNumber.text=#"937-350-5645";
phoneNumber.textColor=[UIColor blueColor];
phoneNumber.font= [UIFont fontWithName:#"ComicSansMsBold" size:18];
[self.view addSubview:phoneNumber];
btnSite = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnSite addTarget:self action:#selector(Site:) forControlEvents:UIControlEventTouchUpInside];
[btnSite setTitle:#"www.midwestsleepmed.com" forState:UIControlStateNormal];
btnSite.frame = CGRectMake(1,370,320,22);
[self.view addSubview:btnSite];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation{
return YES;}
enter code-(IBAction)Begin:(id)sender{
SecondView *sV = [[SecondView alloc] init];
[self.navigationController pushViewController:sV animated:YES];
[sV release];}
`-(IBAction)Site:(id)sender{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://www.midwestsleepmed.com"]];}
pragma mark AppDelegate
pragma mark -
#implementation MidWestSleepAppDelegate
#synthesize window;
#synthesize viewController;
#synthesize score;
- (void)applicationDidFinishLaunching:(UIApplication *)application{
LogMethod();
// If you want the status bar to be hidden at launch use this:
// application.statusBarHidden = YES;
//
// To set the status bar as black, use the following:
// application.statusBarStyle = UIStatusBarStyleBlackOpaque;
// Create window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// this helps in debugging, so that you know "exactly" where your views are placed;
// if you see "red", you are looking at the bare window, otherwise use black
// window.backgroundColor = [UIColor redColor];
viewController = [ [ MainViewController alloc ] init ];
navigationController = [ [ UINavigationController alloc ] initWithRootViewController: viewController ];
/* Anchor the view to the window */
[window addSubview:[navigationController view]];
/* Make the window key and visible */
[window makeKeyAndVisible];}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation{
return YES;}
#end
In above code when i implement then i get problem in simulator that is in landscape mode whole uiview becomes different and not getting their own position. What it is problem in this code and how do I get it fixed?
-(void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:
(UIInterfaceOrientation)fromInterfaceOrientation duration:(NSTimeInterval)duration
{
UIInterfaceOrientation myview=self.interfaceOrientation;
[UIView beginAnimations:#"move Button" context:nil];
if (myview==UIInterfaceOrientationPortrait || myview==UIInterfaceOrientationPortraitUpsideDown)
{ //here is the frames for portrait orientation
coverimage.frame=CGRectMake(2, 2, 315, 310);
myscrollview.frame=CGRectMake(2, 305,320, 480);
}
else
{
//here is the frames for landscape orientation
coverimage.frame=CGRectMake(65,10,330,180);
myscrollview.backgroundColor=[UIColor clearColor];
myscrollview.frame=CGRectMake(2, 150,500,250);
}
[UIView commitAnimations];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation==UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight||
interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}

Can I give a UIToolBar a custom background in my iPhone app?

Is it possible to give a UIToolBar a custom background from an image rather than the usual tinted blue/black fade out?
I've tried giving the view a background and setting the opacity of the UIToolBar but that also affects the opacity of any UIBarButtons on it.
Answering my own question here!!! Overriding the drawRect function and creating an implementation of the UIToolbar does the trick :)
#implementation UIToolbar (CustomImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"nm010400.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
#end
UIToolbar inherits from UIView. This just worked for me:
[topBar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:BAR_BKG_IMG]] autorelease] atIndex:0];
Slightly modified version of loreto's answer, which works for me on ios 4 and 5:
// Set the background of a toolbar
+(void)setToolbarBack:(NSString*)bgFilename toolbar:(UIToolbar*)toolbar {
// Add Custom Toolbar
UIImageView *iv = [[UIImageView alloc] initWithImage:[UIImage imageNamed:bgFilename]];
iv.frame = CGRectMake(0, 0, toolbar.frame.size.width, toolbar.frame.size.height);
iv.autoresizingMask = UIViewAutoresizingFlexibleWidth;
// Add the tab bar controller's view to the window and display.
if([[[UIDevice currentDevice] systemVersion] intValue] >= 5)
[toolbar insertSubview:iv atIndex:1]; // iOS5 atIndex:1
else
[toolbar insertSubview:iv atIndex:0]; // iOS4 atIndex:0
toolbar.backgroundColor = [UIColor clearColor];
}
This is the approach I use for iOS 4 and 5 compatibility:
if ([toolbar respondsToSelector:#selector(setBackgroundImage:forToolbarPosition:barMetrics:)]) {
[toolbar setBackgroundImage:[UIImage imageNamed:#"toolbar-background"] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
} else {
[toolbar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"toolbar-background"]] autorelease] atIndex:0];
}
just add this piece to your -(void)viewDidLoad{}
[toolBarName setBackgroundImage:[UIImage imageNamed:#"imageName.png"] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
If you use idimmu's answer and want your barbuttonitems to be colored instead of the defaults, you can add these couple of lines of code as well to your category:
UIColor *color = [UIColor redColor];
self.tintColor = color;
You can use the Appearance API since iOS5:
[[UIToolbar appearance] setBackgroundImage:[UIImage imageNamed:#"navbar_bg"] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
To be iOS 5 compliant you can do something like this
-(void) addCustomToolbar {
// Add Custom Toolbar
UIImageView *img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"customToolbar.png"]];
img.frame = CGRectMake(-2, -20, img.frame.size.width+4, img.frame.size.height);
// Add the tab bar controller's view to the window and display.
if( SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO( #"5.0" ) )
[self.tabBarController.tabBar insertSubview:img atIndex:1]; // iOS5 atIndex:1
else
[self.tabBarController.tabBar insertSubview:img atIndex:0]; // iOS4 atIndex:0
self.tabBarController.tabBar.backgroundColor = [UIColor clearColor];
// Override point for customization after application launch.
[self.window addSubview:tabBarController.view];
}
this one works fine for me:
ToolbarOptions *tbar = [[ToolbarOptions alloc] init];
[tbar setToolbarBack:#"footer_bg.png" toolbar:self.toolbarForPicker];
[tbar release];
#import <Foundation/Foundation.h>
#interface ToolbarOptions : NSObject {
}
-(void)setToolbarBack:(NSString*)bgFilename toolbar:(UIToolbar*)toolbar;
#end
#import "ToolbarOptions.h"
#implementation ToolbarOptions
-(void)setToolbarBack:(NSString*)bgFilename toolbar:(UIToolbar*)bottombar {
// Add Custom Toolbar
UIImageView *iv = [[UIImageView alloc] initWithImage:[UIImage imageNamed:bgFilename]];
iv.frame = CGRectMake(0, 0, bottombar.frame.size.width, bottombar.frame.size.height);
iv.autoresizingMask = UIViewAutoresizingFlexibleWidth;
// Add the tab bar controller's view to the window and display.
if([[[UIDevice currentDevice] systemVersion] intValue] >= 5)
[bottombar insertSubview:iv atIndex:1]; // iOS5 atIndex:1
else
[bottombar insertSubview:iv atIndex:0]; // iOS4 atIndex:0
bottombar.backgroundColor = [UIColor clearColor];
}
#end
You can do this with a category that basically adds a new property to UIToolBar. Overriding drawRect can work but it's not necessarily future proof. That same strategy for custom UINavigationBar stopped working with iOS 6.
Here's how I'm doing it.
.h file
#interface UIToolbar (CustomToolbar)
#property (nonatomic, strong) UIView *customBackgroundView;
#end
.m file
#import "CustomToolbar.h"
#import
static char TIToolbarCustomBackgroundImage;
#implementation UIToolbar (CustomToolbar)
- (void)setCustomBackgroundView:(UIView *)newView {
UIView *oldBackgroundView = [self customBackgroundView];
[oldBackgroundView removeFromSuperview];
[self willChangeValueForKey:#"tfCustomBackgroundView"];
objc_setAssociatedObject(self, &TIToolbarCustomBackgroundImage,
newView,
OBJC_ASSOCIATION_RETAIN);
[self didChangeValueForKey:#"tfCustomBackgroundView"];
if (newView != nil) {
[self addSubview:newView];
}
}
- (UIView *)customBackgroundView {
UIView *customBackgroundView = objc_getAssociatedObject(self, &TIToolbarCustomBackgroundImage);
return customBackgroundView;
}
#end
In your view controller code, e.g. viewDidLoad
if (self.navigationController.toolbar.customBackgroundView == nil) {
self.navigationController.toolbar.customBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"navigation_bar_background.png"]];
self.navigationController.toolbar.customBackgroundView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
}