I'm getting some odd behaviour with my custom tab bar. The images seem to be aligned incorrectly. Here is a screenshot (I have removed my own tab bar background to highlight my problem):
Here is the code I'm using to set the images for each state:
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:homeNavController, whatsOnNavController, mapNavController, infoNavController, nil];
self.tabBarController.delegate = self;
// For iOS 5 only - custom tabs
if ([self.tabBarController.tabBar respondsToSelector:#selector(selectedImageTintColor)])
{
// Set the background images
//[[UITabBar appearance] setBackgroundImage: [UIImage imageNamed:#"nav_bg.png"]];
[[UITabBar appearance] setSelectionIndicatorImage:[UIImage imageNamed:#"nav_over.png"]];
[homeNavController.tabBarItem setFinishedSelectedImage:[UIImage imageNamed:#"nav_home_over"] withFinishedUnselectedImage:[UIImage imageNamed:#"nav_home"]];
[whatsOnNavController.tabBarItem setFinishedSelectedImage:[UIImage imageNamed:#"nav_whats_on_over"] withFinishedUnselectedImage:[UIImage imageNamed:#"nav_whats_on"]];
[mapNavController.tabBarItem setFinishedSelectedImage:[UIImage imageNamed:#"nav_map_over"] withFinishedUnselectedImage:[UIImage imageNamed:#"nav_map"]];
[infoNavController.tabBarItem setFinishedSelectedImage:[UIImage imageNamed:#"nav_info_over"] withFinishedUnselectedImage:[UIImage imageNamed:#"nav_info"]];
}
All of my replacement tab images are correctly sized (49 pixels high and 80 pixels wide for the non-retina versions).
What could be causing this odd behaviour?
--- Update ---
Here is an updated screenshot with the background in place:
There is a property on UIBarItem (UIBarButton item inherits from this class) imageInsets.
To use full height images (49px) for finishedSelectedImage and finishedUnselectedImage you need to set these image insets:
tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0);
You can fix this in Storyboard now. Storyboard size inspector image inset adjustment
Select the Tab Bar Item you want to adjust, open the Size Inspector, and adjust the Top and Bottom Image Insets. You need to adjust them the same amount or they will just squish/stretch your image (so +5 in Top, and -5 in Bottom)
This may seem a bit hackish but I believe it's the only way you can achieve what you want: you just need to use tab bar finished images which have a transparent 11 pixels "top padding" (22 pixels for retina). Your images will then have to be 60px (120px) high.
My app made it to the App Store using this technique, so you should be safe to use it.
Hope it helps!
It turns out that you should always have text inside a tabitem. The space was created by blank text.
This API is really poorly documented.
Your finishedSelectedImage should be an icon ~30x30 px. This is just the icon part of the tab. If you create a finishedSelectedImage that's too tall, the system will not put it right at the bottom of the screen.
Conceptually, you start with a full-width, 49px high backgroundImage for the tabBar, add a single-tab-width, 49px high selectionIndicatorImage which functions as the background image for the selected tab, then add a two versions of each tab's icon ~30x30 px, finishedUnselectedImage and finishedSelectedImage.
If you add the image as a subview instead with frames defined, can help you out.
Check this
Try using slightly smaller images, tabbar repositions them slightly
Related
I am creating an iOS 7 app in which I'd like to have a SearchBar right bellow the NavigationBar, and I wanted them both to look like a single piece. Therefore I need to tint them with the same color (done already) and remove that hairline at the bottom of the NavigationBar and at the top of the SearchBar. How can I achieve that?
Officially, this is only possible by setting the shadowImage of the navigationBar to an empty image. However, a closer look at the documentation, it is said:
For a custom shadow image to be shown, a custom background image must also be set with the setBackgroundImage:forBarMetrics: method. If the default background image is used, then the default shadow image will be used regardless of the value of this property.
By using a custom background image, you would lose the blurred background translucency.
If you feel adventurous, the "hairline" is a UIImageView that is a subview of the navigation bar. You can find it and set it as hidden. This is what Apple does in their native calendar app, for example. Remember to show it when the current view disappears.
use following code in AppDelegate (didFinishLaunchingWithOptions)
Swift :
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .any, barMetrics: .default)
UINavigationBar.appearance().shadowImage = UIImage()
Objective c :
[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init]
forBarPosition:UIBarPositionAny
barMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
Swift 3:
self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")
One way to remove the hairline on the top and bottom of a UISearchBar is to replace the background image with a stretchable one, that does not have that thin border. Simply make a square shaped png with the color of your choice, then:
[searchBar setBackgroundImage:[[UIImage imageNamed:#"SearchBarImage"] resizableImageWithCapInsets:UIEdgeInsetsMake( 10, 10, 10, 10)]];
Since the background is solid you can use pretty much whatever values you want for the insets.
For those who interested how to implement "adventurous" approach of #Leo Natan, I added the sample code in my answer to the similar question.
I'm trying to customize my navigation bar, and have 2 bar button items that need to display icons. I've just created the bar button items in storyboard and set each one's image as the icon. The icons are both correctly sized pngs (20 x 20pt), however they are displaying much larger than they should be so they look stetched in both directions on the nav bar.
I'm doing everything in storyboard, except I had to add some code in the viewDidLoad method. I'm not sure if that effects anything, but here it is:
//Make the navigation bar transparent
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
self.navigationController.view.backgroundColor = [UIColor clearColor];
//Setup navigation bar with Avenir Next Regular font and white title color
[self.navigationController.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:#"AvenirNext-Regular" size:17], NSFontAttributeName, nil]];
[self.navigationController.navigationBar setTitleTextAttributes:#{NSForegroundColorAttributeName : [UIColor whiteColor]}];
I'm a coding newbie, and this is my first question here. I'd post in image to illustrate the problem but I need 10 reputation points to do that.
Thanks in advance for any help!
You have to provide the images in several resolutions for different devices. The easiest way to do this is to use the xcassets folder in Xcode and fill in all the templates: normal size, 2x, 3x.
If you don't want to use the xcassets you have to name the files yourself:
image.png
image#2x.png
image#3x.png
Xcode chooses the correct size automatically.
Is there any way to adjust the position of the UITabBar badge in iOS 7? The badge now blocks the tab bar icon a bit more than I would like.
iOS 6:
iOS 7:
It looks like the badge is placed in a certain position relative to the image. So if you have no image, the badge is in the upper left corner of the tabBarItem.
So - to position the badge, adjust the border of blank pixels around the .png you're using for the tabBarItem image.
If possible, can you provide the method by which you are setting the tab bar image?
I had the same problem that you did, and fixed it by using UIImageRenderingModeAlwaysOriginal:
UIImage *image = // Your tab bar item image
UIImage *selected = // Your selected tab bar item image
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
selected = [selected imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
controller.tabBarItem = [[UITabBarItem alloc] initWithTitle:title
image:image
selectedImage:selected];
Cheers!
It's not possible to adjust appearance of the badge.
If you really want to have it different, I think implementing custom overlay on UITabBar should be pretty easy. That way you could put there any custom text, not just numbers.
iOS 7 SDK depreciate 3 key method we used to customize tabbar
- (void)setFinishedSelectedImage:(UIImage *)selectedImage withFinishedUnselectedImage:(UIImage *)unselectedImage
- (UIImage *)finishedUnselectedImage
- (UIImage *)finishedSelectedImage
They suggest their alternatives in docs as #Daniel Amitay suggests.
Documentation is here
https://developer.apple.com/library/ios/documentation/uikit/reference/UITabBarItem_Class/DeprecationAppendix/AppendixADeprecatedAPI.html#//apple_ref/occ/instm/UITabBarItem/setFinishedSelectedImage:withFinishedUnselectedImage:
I am creating an iOS 7 app in which I'd like to have a SearchBar right bellow the NavigationBar, and I wanted them both to look like a single piece. Therefore I need to tint them with the same color (done already) and remove that hairline at the bottom of the NavigationBar and at the top of the SearchBar. How can I achieve that?
Officially, this is only possible by setting the shadowImage of the navigationBar to an empty image. However, a closer look at the documentation, it is said:
For a custom shadow image to be shown, a custom background image must also be set with the setBackgroundImage:forBarMetrics: method. If the default background image is used, then the default shadow image will be used regardless of the value of this property.
By using a custom background image, you would lose the blurred background translucency.
If you feel adventurous, the "hairline" is a UIImageView that is a subview of the navigation bar. You can find it and set it as hidden. This is what Apple does in their native calendar app, for example. Remember to show it when the current view disappears.
use following code in AppDelegate (didFinishLaunchingWithOptions)
Swift :
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .any, barMetrics: .default)
UINavigationBar.appearance().shadowImage = UIImage()
Objective c :
[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init]
forBarPosition:UIBarPositionAny
barMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
Swift 3:
self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")
One way to remove the hairline on the top and bottom of a UISearchBar is to replace the background image with a stretchable one, that does not have that thin border. Simply make a square shaped png with the color of your choice, then:
[searchBar setBackgroundImage:[[UIImage imageNamed:#"SearchBarImage"] resizableImageWithCapInsets:UIEdgeInsetsMake( 10, 10, 10, 10)]];
Since the background is solid you can use pretty much whatever values you want for the insets.
For those who interested how to implement "adventurous" approach of #Leo Natan, I added the sample code in my answer to the similar question.
In my app I have a UITabBarController in which I give custom selected/unselected images in my AppDelegate as follows:
UIImage *selectedImage = [UIImage imageNamed:#"home-tab-selected"];
UIImage *unselectedImage = [UIImage imageNamed:#"home-tab"];
UITabBar *tabBar = tabController.tabBar;
UITabBarItem *item1 = [tabBar.items objectAtIndex:0];
[item1 setFinishedSelectedImage:selectedImage withFinishedUnselectedImage:unselectedImage];
The images I have are 100x100, much larger than the normal tab bar items. All works well, and my images are placed nicely and look great.
The issue I am having is that the frame of the underlaying UITabBarButton remains 76x48, leaving only a small portion of my tabs 'touchable'. (Image below with a border around the frame)
To attempt to fix this, in my subcalssed UITabBarController viewDidLoad, I go through each UITabBarButton, and set the frame as follows:
for (UIView* subView in self.tabBar.subviews)
{
if ([subView isKindOfClass:NSClassFromString(#"UITabBarButton")])
{
[subView setFrame:CGRectMake(subView.frame.origin.x, subView.frame.origin.y, 100, 100)];
}
}
After I do that, I log the frames and they do change-- BUT the frame never changes in my tab bar-- I still only see and can touch in the smaller red box.
Is this because Apple does not allow you to change these frames or am I doing something wrong here?
Any help apperciated! Thanks!
EDIT:
In the end I just ended up making my tab images smaller. I found a height of 70px still picks up most touches.
The layout of your UITabBarController's view might change after loading: Additional UITabBarItems could be added, of the user could switch to landscape orientation.
Before iOS 6, there wasn't a way to configure complex layouts. Since UITabBar is a very old class, it's most likely doing its work in the layoutSubviews method.
You could subclass UITabBar and override said method, but if you go that far, you might want to think about creating your own tab bar, which in the end is just a UIView with a few UIButtons.
Had a similiar problem with the underlying UITabBarButtons. I solved it by setting the UITabBar's "Item positioning" attribute to "Fill".