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".
Related
Let me explain my situation first. I set the UINavigationBar color in my appDelegate Like:
[[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:255.0f/255.0f green:87.0f/255.0f blue:10.0f/255.0f alpha:1]];
Now in my some viewController the translucent of UINavigationBar set as YES.
self.navigationController.navigationBar.translucent = YES;
That's why there is a shade over my UINavigationBar. It wasn't showing the exact color. As a solution, I set translucent from YES to NO. It is showing the exact color now, But I am facing that some of my view completely gone from my interface. Here, let me tell you one thing that, so many of views here, is positioned by programmatically, so I am afraid I can't just move every of my viewControllers view 64 px high. Just wondering is there any solution to solve the thing. I try with opaque, but no luck. If any one understand my problem please share the solution if you have. Thanks a lot in advance.
From iOS7 if you use a translucent bar ( in UINavigationController or UITabbarController) the hosted view controller has as default behavior to extend under them. If you say to set the bar as translucent the color of it it will be a combination of the view under it and bat color. That is normal and the only way is to set translucency to no or apply a background image to navigation bar.
Applying frames manually will lead to unexpected result under auto layout, you must use constraints.
[UPDATE]
To create a background image from a solid color you can use that method, the image is 1px square, but there is no problem because it can be stretched or tiled to cover the entire area:
+ (UIImage *) imageWithColor:(UIColor*) color {
CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
UIImage *colorImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return colorImage;
}
If you see and extra gap is probably because you have also set automaticallyAdjustScrollViewInset to YES, try setting it NO. This property add and extra inset to your view or your vfirst view subview if it inherits from a UIScrollView
Its late, but i face same issue, and i resolved it by making UINavigationbar none on Viewcontroller in storyboard, and resized the view to start from 0,0
Hey I am using a custom sized UITabBar with extra large images.
I add the images to the tab bar item like this:
UITabBar *tabBar = self.tabBar;
UITabBarItem *tabBarItem1 = [tabBar.items objectAtIndex:0];
[tabBarItem1 setImage:[UIImage imageNamed:#"image"]];
[tabBarItem1 setImageInsets:UIEdgeInsetsMake(0, 0, 20, 0)];
Also because the images are larger I want them to hover more in the middle of the tab bar, so I add the inset.
My issue is when I program the inset and then click on the button, the button squishes in on its self. It maintains its width, but its height squishes in on its self. I of course don't want this to happen, but I can't seem to find out whats going on.
Thanks, Krtko
-Note for Mods Please lock this thread
-Note for people answering my question. I appreciate your help but it was a known bug at the time, so please stop answering this question. Thank you
Are you seeing this on iOS 7 only?
7.1 seemed to introduce a bug with tab bar image insets. If you continually tap or hold the tab, it grows or shrinks depending on the insets. If you tap on another tab, the tab bar image goes back to normal right?
When using UIEdgeInsetsMake the important point is to have the top inset "BE EQUAL" to the bottom inset.
For example : item.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0);
Remove your insets for the image. Use an image that is exactly of the size you want. We have to follow this approach till Apple fixes this issue.
You may put a UIView on top of the tab bar, and add a UITapGestureReognizer to the UIView. When tapped, I determine where it is and call the appropriate selected item for the tabbar. Hack, but works quite nicely and lets you keep your inset values to whatever you want.
#property UIView tabBarCover;//place on top of uitabbar and give it clear color background
- (void)viewDidLoad
{
[tabBar setSelectedItem:[tabBar.items objectAtIndex:0]];
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[tabBarCover addGestureRecognizer:singleFingerTap];
}
Then each time the UIView is tapped, set the selected item based on where the user touched. I had 3 tab bar items, so I just did some logic for the x coordinate.
-(void) handleSingleTap:(UITapGestureRecognizer *) recognizer
{
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
//NSLog(#"tapped it %lf", location.x);
if(location.x<=105){
//1st 3rd tapped, do something
}
else if(location.x >105 && location.x<=210)
{
//do nothing, selected item stays same. this is glas
}else{
//must be in 3rd section so do that load
}
}
Hope it helps.
You just check if ios7 then setFrame again inside
(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
I want to developer app with a custom navigation bar like in the following images:
I think that i need to subclass UINavigationBar and add button to centre of nav bar, but i don't really know how to make navigation bar look like on image. Can you please give me advice what should i do, links to any kind of documentation would be awesome!
Similar questions about navBar that doesn't helped me:
ios back button in the bar
Use custom Navigation Bar in iOS
Custom Navigation Bar in iOS 5
rogcar
EDIT:
My idea is next: make custom navigation bar height little bigger than default size, and add background image with arrow in it and with some transparency on the edges.
If you want a button (you probably do want) you can achieve it completely by subclassing UINavigationBar. You should remember that height of UINavigationBar is read-only property.
Style but not tappable:
So let's assume we subclass the navigation bar and add button there. You could do this and it will be going look great. For example:
- (void)drawRect:(CGRect)rect
{
self.backgroundColor = [UIColor lightGrayColor];
UIButton *myButton = [[UIButton alloc] initWithFrame:CGRectMake(self.frame.size.width/2-50, 0 , 100, 100)];
[myButton setBackgroundColor:[UIColor lightGrayColor]];
[myButton setTitle:#"Normal" forState:UIControlStateNormal];
[myButton setTitle:#"Highlighted" forState:UIControlStateHighlighted];
[self addSubview:myButton];
[self sendSubviewToBack:myButton];
}
But you will facing a problem that your button is non tapeable below UINvaigationBar. (I post an image on the bottom of the answer)
So there is clearly not a path you want to follow. Don't even try that.
Style but not tappable 2:
You may override this method in your navigation bar subclass
- (CGSize) sizeThatFits:(CGSize)size {
return CGSizeMake(custom_width, custom_height);
}
And then mask it using UIBezierPath for example
The right (tappable) way:
You have to create a view stick to your UINavigationBar. What i will do here (if you want it to every screen) is:
Make a Category of UIViewController which can draw (for example - this is easiest way) UIButton.
Style this 'UIButton' whatever you want (if you want
Pin action to 'UIButton': [btn addTarget:self action:#selector(menuShow:) forControlEvents:UIControlEventTouchUpInside];
menuShow: method should be declare in your category
You can call drawing button every time you want to redraw view controller.
As you can see there there will be two separates View: UINavigationBar and UIButton. This is allow you to set content under this little button and make it tapable.
So why just don't hide navigation bar, and use different view? Because iOS7 ;) When Apple change it in iOS7 for example then you have to rebuild your pseudo NavigationBar, with only additional view, you don't need to do anything.
You do not need to subclass UINavigationBar. Create UIView add to it UIImageView as background with image in the shape you need, add button.
Subclass UINavigationController hide UINavigationBar, add custom navigation bar.
First Hide navigation bar using -
self.navigationController.navigationBarHidden = YES;
Then create UIView with required height,height of navigationBar is 44px.Then create background image view, object of required UIButton and add all objects on created UIView as a subview.It will look like navigationBar.Thank you.
You can add your custom shaped view as titleView on the navigation bar.
Just make sure that clipsToBounds is set to NO, so it doesn't get clipped.
I have an app where up until now I've been using a UINavigationController with a UINavigationBar that has its property translucent = YES. This means the UINavigationController's content view (i.e. the views from the view controllers you push) to be full-screen (minus status bar).
However, if you set the navigationBar.translucent = NO, this container view becomes 44pt shorter, as I suppose Apple has assumed you don't need any content under an opaque navigationBar.
... except if you're doing what we're doing and are employing a navigationBar that scrolls away (see This Post on how to do that) So I'd like to know if this is possible.
I want to have translucent = NO, but have everything behave as if it were still set to YES. I like the functionality of the translucent = YES, but I don't actually want the bar to be made translucent by UIKit.
What worked for me was to add
extendedLayoutIncludesOpaqueBars = true
in
viewDidLoad
something like this
override func viewDidLoad() {
super.viewDidLoad()
extendedLayoutIncludesOpaqueBars = true
}
Hope it will work for you as well
It's not necessarily a good answer but you could just offset your view that high if you're not translucent.
//This won't take into account orientation and probably other details
if(!self.navigationController.navigationBar.isTranslucent)
{
self.view.frame = CGRectMake(0,0,-44,self.view.bounds.size.height);
}
You could put that in your viewDidLoad or viewWillAppear and if you have a bunch of view controllers you can just subclass them all and put your logic in the subclass.
I found a solution that works, although it is indeed a bit of a hack.
The idea is to give the translucent nav bar an opaque backing. Unfortunately I'm not happy with the solution in that it's dirty and not encapsulated and introduces some potential issues, but i AM happy because it got the job done.
In my Application's base view controller class (i.e. MyViewController : UIViewController), in the viewDidLoad method, I instantiate a new ivar UIView *_navigationBarBG and give it the same frame as self.navigationController.navigationBar. I then set it's backgroundColor property to [UIColor whiteColor] although this is how you achieve some more tint I guess. [EDIT:If you wanted to be a purist (color values remaining exactly as they come from the .psd), you could make the _navigationBarBG a UIImageView and use your custom background there, and the background of the actual UINavigationBar you set to draw clear (or stretch a 1px transparent image if you wanted to use a typical 'change your navigation bar using an image' recipe that's somewhere on the internet)]
if(self.navigationController)
{
_navigationBarBG = [[UIView alloc] initWithFrame: self.navigationController.navigationBar.frame];
_navigationBarBG.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_navigationBarBG];
}
THEN, (and this is the crappy part, but I don't see any other way), I add this view as a subview. BUT, whenever you would normally make a call to [self.view addSubview: anyView], you have to make sure you call [self.view insertSubview: anyView belowSubview: _navigationBarBG];
if (_navigationBarBG)
[self.view insertSubview: anyView belowSubview:_navigationBarBG];
else
[self.view addSubview: anyView];
If you forget that, these added views will slide under your navbar background and look weird. So you need to know that this is a source of error.
WHY AM I DOING THIS? Again you might ask... I want to be able to have a scrolling navigation bar that scrolls out of the way when you scroll down your table view, thereby giving the user more screen space. This is done by using the scrollView delegate (scrollViewDidScroll:) and also viewWillAppear:
// FIRST DEAL WITH SCROLLING NAVIGATION BAR
CALayer *layer = self.navigationController.navigationBar.layer;
CGFloat contentOffsetY = scrollView.contentOffset.y;
CGPoint newPosition;
if (contentOffsetY > _scrollViewContentOffsetYThreshold && self.scrollingNavigationBarEnabled) {
newPosition = CGPointMake(layer.position.x,
22 - MIN((contentOffsetY - _scrollViewContentOffsetYThreshold), 48.0)); // my nav bar BG image is 48.0 tall
layer.position = newPosition;
[_navigationBarBG setCenter: newPosition]; // if it's nil, nothing happens
}
else
{
newPosition = kNavBarDefaultPosition; // i.e. CGPointMake(160, 22) -- portrait only
layer.position = newPosition;
[_navigationBarBG setCenter: newPosition]; // if it's nil, nothing happens
}
I was looking for an answer to this as I wanted my subviews to be at (0,0) and not (0,44)(in reference to the Screen bounds), but I could not find an answer on how to set this in the NavigationController, which I thought would be an included property.
What I ended up doing that was very simple is adding a subview to the navigation controller that was the width and height of the Navigation Bar, but then insert the subview below the Navigation Bar.
Now the setting is Translucent = YES, but it still appears solid and the subviews behave how I want.
EDIT: After re-reading your original post, I suppose if you're going to be rolling the nav bar away, you'll have to take into account hiding and showing the new subview as you do the same with the nav bar
I want to add a image just above the navigation bar. Here is the final result picture I want:
click me
At the beginning, I think it is quite simple:
Using UIBuilder add one UIImage and one UIView
Add navigation bar controller to UIView as its root view
The Hierarchy I thought should like this: UIViewController->UIView->NavigationBarController.(Here the UIView is one subview of the view of UIViewController)
Below is one of the code I tried, subView is the IBOutlet of one UIView builed by UIBuilder
UINavigationController *test;
test=[[UINavigationController alloc]init];
[[subView window] setRootViewController:test];
[subView.window makeKeyAndVisible];
But after trying several times,I found it is not working.
Does anyone do the same work before? If so, please give me some suggestions.
self.navigationController.navigationBar.frame = CGRectMake(0, //height of imageView//, self.view.bounds.size.width, 44.0f);
CodaFi's suggestion is almost there.
Try this:
test.view.frame = CGRectMake(0, //height of imageView//, self.window.bounds.size.width, //(total height of content... e.g. 460.0f if you leave the status bar visible)-(height of imageView)//);
There is one thing to note though... The navigation controller likes to take up all the usable space on screen so sometimes it will automatically resize its view to a rect like this, {{0.0f,0.0f},{320.0f,460.0f}} after rotating the device. I have experienced this many times on the iPad. You might have to start listening for the rotation event, and reset the frame of the navigation controller's view on every rotation to one that doesn't block your image.