What would be the best way to create a completely custom UITabBarController look alike.
I need full customization of its size, animate it, etc.
A solution that I have is just using a UIView for the tabbarcontroller that then replaces the UIView above it depending on what button is selected on that UIView.
What is the best approach?
This is a pretty good guide for doing just that:
http://www.felipecypriano.com/2012/02/27/how-to-customize-uitabbar-on-ios-5/
This example is taken from that site:
Basically create a backgroundImage, selectionIndicatorImage, adjust the fonts as appropriate.
// Probably put these in your AppDelegate, setup the background and selection image
[[[self tabBarController] tabBar] setBackgroundImage:[UIImage imageNamed:#"background"]];
[[[self tabBarController] tabBar] setSelectionIndicatorImage:[UIImage imageNamed:#"selected"]];
// In your VC which is inside the tab bar
- (id)init {
self = [super initWithNibName:#"MyNibName" bundle:nil];
if (self) {
self.tabBarItem = [[UITabBarItem alloc] initWithTitle:#"The Title" image:nil tag:0];
[[self tabBarItem] setFinishedSelectedImage:[UIImage imageNamed:#"tab_icon"] withFinishedUnselectedImage:[UIImage imageNamed:#"tab_icon"]];
[[self tabBarItem] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor], UITextAttributeTextColor, nil] forState:UIControlStateNormal];
}
}
Related
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;
}
I'd like to change the background color of an UINvaigationBar and I used tintColor property but it's not changing the color. You can checkout the code below.
In my Appdelegate I create a UITabBarController
tabbar = [[UITabBarController alloc] init];
Then I create a UINavigationController and attach my UITableViewController to it
UINavigationController *myNavigation = [[UINavigationController alloc] initWithRootViewController:myViewController];
Then attached the UINavigationControllers to my tabbar like this
[tabbar setViewControllers:viewControllers]; //viewControllers is an array of UINavigationControllers
I tried setting the property tintColor in myAppdelegate like this
[[myNavigation navigationBar] setTintColor:[UIColor redColor]];
But this didn't work as expected and so I tried the same in my ViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController.navigationBar setTintColor:[UIColor blackColor]];
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
self.navigationItem.title = #"Test";
}
And still nothing happens. Please checkout the image below to see how navigation bar looks now.
Appreciate your help.
Cheers
Jugs
As a work around you may can use image on place of tint color please check below code for same.
if ([myNavigation respondsToSelector:#selector(setBackgroundImage:forToolbarPosition:barMetrics:)]) {
[myNavigation setBackgroundImage:[UIImage imageNamed:BAR_IMAGE_NAME] forbarMetrics:UIBarMetricsDefault];
}else {
[myNavigation insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:BAR_IMAGE_NAME]] autorelease] atIndex:0];
}
First time poster. Thanks in advance.
I want to use a UITabBar in my iPhone app. I have been led to believe that I cannot use UITabViewController because I would be nesting it inside a UINavigationController. I read that you can do this, but you have to use UITabBar instead of the full-fledged controller. I can make this work with Interface Builder, but I've got a lot of redundant XIBs and I'd rather do it in code anyway. I want to know how the magic works, as it were.
Here's the .m of my controller:
#import "DumbViewController.h"
#implementation DumbViewController
-(void) loadView {
UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 100, 150, 30)];
[label setText:#"hello world"];
[view addSubview:label];
[label release];
UITabBar *tb = [[UITabBar alloc] initWithFrame:CGRectMake(0, [view frame].size.height - 64, [view frame].size.width, 64)];
[tb setDelegate:self];
[tb setItems:[NSArray arrayWithObject:[[[UITabBarItem alloc] initWithTitle:#"bob" image:[UIImage imageNamed:#"21-skull.png"] tag:0] autorelease]]];
[view addSubview:tb];
[tb release];
[self setView:view];
[view release];
}
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
NSLog(#"selected item %#", item);
}
#end
When I run the app, I get my label and a tab bar at the bottom. I get the goofy little skull icon, but "bob" never displays. Clicking the skull works as you would expect.
Why isn't that title showing?
Thanks!
Try the following code....
UITabBarItem *someTabBarItem = [[UITabBarItem alloc] initWithTitle:#"bob" image:[UIImage imageNamed:#"21-skull.png"] tag:0];
NSArray *tabBarItems = [[NSArray alloc] initWithObjects:someTabBarItem,nil];
[tabBar setItems:tabBarItems animated:NO];
[tabBar setSelectedItem:someTabBarItem];
[tabBarItems release];
[someTabBarItem release];
The problem was that I was setting the frame of the UITabBar outside the frame of the parent view.
I added this line after the UITabBar alloc line.
[tb setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
The advantage here is that even if I rotate or if the app is running on an iPad, the tab bar stays at the bottom of the screen.
I also changed from a 64 pixel height to a 44 pixel height because it looks much more like how the XIB did originally.
I have an issue in customizing the appearance of my QLPreviewController.
We can display a QLPreviewController by pushing it in a navigation controller, or presenting it in a ModalViewController. Since my navigationController's bar is customized a little (tintColor), I'm pushing the QLPreviewController to preserve my color scheme. But when I push it, the QLPreviewController seems to have some problems : I need to systematically call [qlpvc reloadData] so that my file is displayed.
In iOS [REDACTED], even with reloadData, nothing displays in the pushing way, (actually it displays but in a random way). So I decided it could be interesting to only use the reliable Modal way.
Soooo my point is that I want to present my QLPreviewController in a ModalViewController. It works great that way, but I can't customize the viewController appearance.
For example in a didSelectRowAtIndexPath if I do :
(I don't have my sources near to me so excuse me if I do a mistake)
QLPreviewController *qlpvc = [[QLPreviewController alloc] init];
qlpvc.dataSource = self; // Data Source Protocol & methods implemented of course
No need for delegate in my case so //qlpvc.delegate = self;
qlpvc.currentPreviewItemIndex = [indexPath.row];
// The following doesn't work :
[qlpvc.navigationController.navigationBar setTintColor:[UIColor redColor]];
// The following doesn't work too :
[qlpvc.modalViewController.navigationController.navigationBar setTintColor:[UIColor redColor]];
[self presentModalViewController:qlpvc animated:YES];
[qlpvc release];
tl ; dr version : How to manage to customize my modal QLPreviewController's appearance ? Especially the tintColor of the navigationBar ?
Thanks a lot.
This works, but I don't know if it will be rejected by Apple as it's not a published method and may break in future versions of the OS. Works in iOS6.
Add to the preview controller datasource method:
- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
for (id object in controller.childViewControllers)
{
if ([object isKindOfClass:[UINavigationController class]])
{
UINavigationController *navController = object;
navController.navigationBar.tintColor = [UIColor colorWithRed:0.107 green:0.360 blue:0.668 alpha:1.000];
}
}
NSString *pathToPdfDoc = [[NSBundle mainBundle] pathForResource:#"MyPDFFile" ofType:#"pdf"];
return [NSURL fileURLWithPath:pathToPdfDoc];
}
Subclass QLPreviewController and change the tintColor, et al in viewDidLoad:.
If you are trying to maintain simple styling such as tintColor throughout your app, you should consider using UIAppearance selectors on many UIView classes. The following example customizes all instances of UINavigationBar, including those displayed in QLPreviewController:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//..
[self initAppearance];
return YES;
}
-(void)initAppearance{
UINavigationBar* defaultNavigationBar = [UINavigationBar appearance];
UIImage *backgroundImage = [UIImage imageNamed:#"MY_IMAGE.png"]
NSDictionary *defaultNavigationBarDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"Futura-Medium" size:19], NSFontAttributeName,
[UIColor blueColor], UITextAttributeTextColor,
[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.0f], UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0.0f, 2.0f)], UITextAttributeTextShadowOffset,
nil];
defaultNavigationBar.titleTextAttributes = defaultNavigationBarDictionary; //iOS5
//[defaultNavigationBar setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault]; //iOS5
[defaultNavigationBar setBarTintColor:[UIColor redColor]]; //iOS7
[defaultNavigationBar setShadowImage:[[UIImage alloc] init]]; //iOS6, removes shadow
[defaultNavigationBar setTitleVerticalPositionAdjustment:0.0f forBarMetrics:UIBarMetricsDefault]; //iOS5
[defaultNavigationBar setBackIndicatorImage:[UIImage imageNamed:#"BACK_ARROW.png"]]; //iOS7
[defaultNavigationBar setBackIndicatorTransitionMaskImage:[UIImage imageNamed:#"BACK_ARROW.png"]]; //iOS7
}
Hope you can help with this one too...
I wanted to customize my navigation bar by adding custom background picture. I found out perfect but a bit complicated method called:NavigationSwizzle. In previous project I worked without any serious problems, but now I'm stuck...
From my AppDelegate I am calling this static method:
#implementation SCAppUtils
+ (void)customizeNavigationController:(UINavigationController *)navController
{
//Customizing navigation BAR
UINavigationBar *navBar = [navController navigationBar];
[navBar setTintColor:kSCNavBarColor];
//Customizing TOOLBAR
[navController setToolbarHidden:NO animated:YES];
UIToolbar *toolBar = [navController toolbar];
UIImageView *imageView = (UIImageView *)[navBar viewWithTag:kSCNavBarImageTag];
UIImageView *imageView2 = (UIImageView *)[toolBar viewWithTag:kSCNavBarImageTag];
if (imageView == nil)
{
Utilities *utilities = [[Utilities alloc]init];
UIImage *img = [UIImage imageNamed:#"nav-bar-background.png"];
UIImage *img2 = [UIImage imageNamed:#"toolbar-background.png"];
imageView = [[UIImageView alloc] initWithImage:img];
imageView2 = [[UIImageView alloc] initWithImage:img2];
[imageView setTag:kSCNavBarImageTag];
[imageView2 setTag:kSCNavBarImageTag];
[navBar insertSubview:imageView atIndex:0];
[toolBar insertSubview:imageView2 atIndex:0];
[imageView release];
[imageView2 release];
[utilities release];
}
}
In rootNavigationController after calling second view controller by pushing it on the stack my right button, self.title, activityIndicator don't show. If I comment or set atIndex:-1 in line [navBar insertSubview:imageView atIndex:0]; then buttons show, but my customized background is gone and I get regular iPhone navigational tab.
In didSelectRowAtIndex of rootNavigationController I have:
//ADD BACK BUTTON TO VIEW
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Home" style:UIBarButtonItemStyleDone target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
//Home Button color
self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:166.0 / 255 green:179.0 / 255 blue:191.0 / 255 alpha:1.0];
//PUSH TO NEXT VIEW
[self.navigationController pushViewController:detailViewController animated:YES];
Thank you in advance...
If you need more code or explanation, please don't hesitate to ask me...
Best regards,
Luka
EDIT:
Ok, I can make this question much simpler. I have a custom background image in my navigation bar. This image is obviously covering my
self.navigationItem.title = #"TITLE";
If I put alpha to: 0.3 of imageView that is in the background I can see my title:
imageView = [[UIImageView alloc] initWithImage:image];
[imageView setAlpha:0.3];
[imageView setTag:kSCNavBarImageTag];
[navBar insertSubview:imageView atIndex:0];
So the question is how can I send my navigationItem.title to front? Is it a UIView class descendent?
EDIT 2:
Really weird thing is that title is visible (above background image) in the rootController but after pushing another viewController title goes behind te background imageView ?!
I honestly think you forgot to add this code in the main.m. You main.m should look something like this:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "SCClassUtils.h"
int main(int argc, char *argv[])
{
[SCClassUtils swizzleSelector:#selector(insertSubview:atIndex:)
ofClass:[UINavigationBar class]
withSelector:#selector(scInsertSubview:atIndex:)];
[SCClassUtils swizzleSelector:#selector(sendSubviewToBack:)
ofClass:[UINavigationBar class]
withSelector:#selector(scSendSubviewToBack:)];
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
You might want to try this to customize your Navigationbar instead. I use it in my apps and it works like a charm
UIImage *theImage = [UIImage imageNamed:#"barImage.png"];
[self.navigationController.navigationBar insertSubview:[[[UIImageView alloc] initWithImage:theImage] autorelease] atIndex:0];
See if that fixes your issues with the buttons not appearing.
I found a solituion for my work. Create a view (viewBackground) with all the images and colors that conform the navigation bar and then y convert it in a image and use it like a background
UIGraphicsBeginImageContextWithOptions(viewBackground.bounds.size, viewBackground.opaque, 0.0);
[viewBackground.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[[UINavigationBar appearance] setBackgroundImage:img forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setBackgroundImage:img forBarMetrics:UIBarMetricsDefault];