Customize UINavigationBar font - ios

I'm trying to customize my UINavigationBar font, using the following code for iOS 5 in my app delegate's application:didFinishLaunchingWithOptions:
if ([[UINavigationBar class] respondsToSelector:#selector(appearance)])
{
[[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor whiteColor], UITextAttributeTextColor,
[UIColor blackColor], UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(1, 0)], UITextAttributeTextShadowOffset,
[UIFont fontWithName:kDefaultFont size:0.0], UITextAttributeFont,
nil]];
}
It works fine and the navigation bar is rendered using my font. Great.
The references I've found suggest that you can use the font size of zero and it will resize the font to fit your navigation bar (using a slightly smaller font for the shorter navigation bar for the landscape layout). And it does choose a font size that fits nicely to the height of the navigation bar. But it looks like if you go from portrait to landscape and back, the width of the navigation bar's title label gets screwed up, so what shows up as a title of, for example, "Long Titlebar", looks fine when you first view it in portrait orientation, looks fine when you view it in landscape (with the appropriately smaller font), but when I come back to portrait, the font correctly reverts to the larger font, but the title text itself is truncated, becoming "Long..." even though there's plenty of space for the full title. Has anyone else seen this behavior when using a font size of 0.0?
Clearly, I can just specify an actual font size (in which case I don't see this truncating behavior), but then I'm manually figuring out what size to use. And worse, the font size is the same for landscape and portrait, so right now I'm using a font size that fits in the shorter landscape navigation bar title and the title is smaller than it needs to be in the taller portrait navigation bar.
Has anyone out there had experience with using setTitleTextAttributes to change the font of the [UINavigationBar appearance] in such a way that the font size changes between portrait and landscape, but not having this truncation of the title when you return back to portrait after going to landscape? I'm about to pursue various kludgy workarounds, but if you have any experience in this issue, let me know.
Update:
In the process of submitting this bug to Apple, I decided to demonstrate how to reproduce the problem:
Create new iOS Master-Detail Application in Xcode 4.3.2.
Put the above setTitleTextAttributes code in the app delegate's application:didFinishLaunchingWithOptions (I used the font #"GillSans").
Go to MasterViewController and add line that says self.title = #"Long Title";
Comment out the UIBarButtonItem *addButton code.
Run the program. Note the title correctly says "Long Title". Rotate to landscape. Still looks good. Rotate back to portrait and the title now says "Long..." even though there's plenty of space.
Curiously, if you restore the UIBarButtonItem *addButton code, the title works as it should. But if you either eliminate the UIBarButton item, or replace it with a button that uses initWithTitle rather than initWithBarButtonSystemItem, you get the problem with the navigation bar title after rotating from portrait to landscape and then back to portrait.

By the way, I neglected to point out that Apple replied to my bug report, acknowledging that this was a known issue. Hopefully it will be resolved soon!

the following is my workaround for this problem, and here's the comment that appears next to my workaround implementation in each case as a reminder to myself as to why i implemented this bit of code:
// when using an appearance proxy to set a custom font for the navigation bar (generally in
// application:didFinishLaunchingWithOptions: in the appDelegate code) for both iOS 5 & 6,
// there's a glitch that incorrectly auto-truncates the title in the following cirumstances:
//
// 1) when a 0.0 value is used for UITextAttributeFont in the titleTextAttributes dictionary
// and a device/simulator running pre-iOS 5 rotates back to portrait from landscape
// solution: perform [self.navigationController.navigationBar setNeedsLayout] in
// didRotateFromInterfaceOrientation: the view controller in which the
// auto-truncation is incorrectly occurring for systemVersion < 6.0
//
// 2) when a view initially loads running iOS 6 for a non-0.0 value for the UITextAttributeFont
// in the titleTextAttributes dictionary
// solution: perform [self.navigationController.navigationBar setNeedsLayout]
// in viewDidLoad in the view controller in which the auto truncation is
// incorrectly occurring for systemVersion >= 6.0
so, for the cases where i'm ok with using the 0.0 value for UITextAttributeFont but have to continue supporting iOS5, i use solution (1):
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
&& UIDevice.currentDevice.systemVersion.floatValue < 6.0)
[self.navigationController.navigationBar setNeedsLayout];
}
#endif
and in the couple of cases of legacy code where i wanted to support iOS 6 and fix the glitch when the view first appears without having to re-write the MyAppAppearance class methods i have that set non-0.0 values for my [UINavigationBar appearance] titleTextAttributes, i found it easier to implement the solution (2) thus:
- (void)viewDidLoad
{
[super viewDidLoad];
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
if (UIDevice.currentDevice.systemVersion.floatValue >= 6.0)
#endif
[self.navigationController.navigationBar setNeedsLayout];
// … other viewDidLoadCode
(and the __IPHONE_OS_VERSION_MIN_REQUIRED bracket just helps remind me which code can eventually go away if desired in the future, and which may have to stay.)
to see a little more exactly what happens here, particularly in the case of the rotation, run the simulator with slow animations toggled.

I think a good solution is to refresh the title of your Navbar after a device rotation. Something like
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
self.navigationItem.title = #"Your title";
}
Hope this helps!

Based on the response from #Abramodj (which doesn't work), I tried this. Presumably nothing was happening in that solution as the system notices that the text hasn't actually changed. Switching to nothing and back again sorts it out.
Tested as definitely working on iOS5.0.
// iOS5 has a bug where if you switch orientation the title bar text gets cut off...
-(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
self.navigationItem.title = #"";
self.navigationItem.title = #"Your Title";
}

The bug where a UINavigationBar title text is cut off after applying changes via appearance can happen even if you're not doing orientation switching like Ben Clayton describes. I've seen this problem occur on an app that only supports portrait orientation.
[self.navigationItem setTitle:#""];
[self.navigationItem setTitle:#"The real title"];
Will work just fine even in such a case.
By the way, I've had this issue since iOS 5. Just tested it right now in iOS 6 and IT'S STILL THERE. What the heck, Apple?

Related

iOS Navigation Bar Height

novice iOS developer and I am trying to figure out why my Navigation bar height wont change after I programmatically change it. I have done the following things:
I added this piece of code to the AppDelegate.m in the didFinishLaunchingWithOptions method
[[UINavigationBar appearance] setFrame:CGRectMake(0, 0, 320, 200)];
I was told that this would create a much larger navigation bar but it doesn't seem to be doing so.
I have also added the following code in a specific view controller (FirstViewController.m) to change the font family, text color, etc.
-(void)awakeFromNib {
[[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:(72/255.0) green:(167/255.0) blue:(192/255.0) alpha:1]];
[self.navigationController.navigationBar setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"CaviarDreams" size:28], NSFontAttributeName,
[UIColor whiteColor], NSForegroundColorAttributeName, nil]];}
Am I doing something wrong here?
Any help would be great!!
You can change the height of a navigation bar if it is your navigation bar - if it's just a free-standing interface object.
But if you're using a UINavigationController, the height of the navigation bar is really not up to you. The UINavigationController does the layout of views, and you can't really change what it does. That is part of the price of using this built-in structure, if you see what I mean.
As for your other attempts, you are probably doing them at the wrong time. For example, in awakeFromNib it makes no sense to talk about self.navigationController.navigationBar as it is probably nil anyway at that time (you can easily check with logging). That is why it is better to use the appearance proxy. But then you are doing that too late; you have to use the appearance proxy in application:didFinishLaunching...:, because it affects only future instances of that type.
Basically as a newbie you need to learn what Cocoa lets you do and what it doesn't, and when are the right moments in the process to do those things. It's a big framework. You're in bed with a gorilla; you need to know when the gorilla wants to turn over and let it turn over, or you'll just get squashed. You'll get better at this as you become more accustomed to it.

Why my Bar Button item isn't getting hidden?

I'm using UIBarButtonItem in my project. I've tried to hide the UIBarButtonItem in iOS 6.1, but I was unable to do the same using the following code:
barbuttonname.tintColor = [UIColor clearColor];
barbuttonname.enabled = NO;
This code hides the UIBarButtonItem in iOS 7.1, but in iOS 6.0 it shows the UIBarButtonItem. How can this issue be fixed?
The reason is because use of tintColor for that purpose only became available in iOS 7. in iOS 6, the buttons also typically have borders and backgrounds and each bit is handled separately. In terms of what you're actually trying to accomplish here, I think you should go about it a different way.
Instead of modifying properties on the button to hide it, simply remove it from the navigation bar or wherever you have it. For example, if it is the right button on a UINavigationBar, you would just do:
myNavigationBar.rightBarButtonItem = nil;
Then, when you want to show it again
myNavigationBar.rightBarButtonItem = myButtonItem;

Prevent UiNavigationBar Title from getting Cut off?

I am trying to customize the appearance of the navigationBar title in my ios application. This is the code I currently have:
NSMutableDictionary *navigationTitleAttributes = [NSMutableDictionary dictionary];
[navigationTitleAttributes setValue:[UIColor whiteColor] forKey:UITextAttributeTextColor];
[navigationTitleAttributes setValue:[UIColor clearColor] forKey:UITextAttributeTextShadowColor];
[navigationTitleAttributes setValue:[NSValue valueWithUIOffset:UIOffsetMake(0.0, 0.0)] forKey:UITextAttributeTextShadowOffset];
[navigationTitleAttributes setValue:[UIFont fontWithName:#"Calibri" size:30] forKey:UITextAttributeFont];
[[UINavigationBar appearance] setTitleTextAttributes:navigationTitleAttributes];
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:-8 forBarMetrics:UIBarMetricsDefault];
The code yields the following effect:
It works great but my title gets cut off from the bottom.
I've seen solutions to this problem that use a custom UIView (such as this one: UINavigationbar title is cut off when using titleTextAttributes). However, that particular solution requires that the titleView property of the navigation bar be updated for each screen.
I was wondering if there was a simple solution that would cascade through my entire application.
Thanks
Th simple solution is to not use such a large font size. If you set the size to zero then the text should be auto-sized as appropriate.
Otherwise, using a custom view is the correct solution. You can subclass the navigation controller or navigation bar in order to ensure that all of the views have the label styled in the same way.
If you're using a custom font, you may be having the same problem I was. I found a few answers on this post to be quite helpful. I changed my descender values in my .otf font file to prevent my font from being cut off on the bottom. It was especially prevalent in iOS 7.
Custom installed font not displayed correctly in UILabel

Changing appearance of UIBarButtonItem also changes position of navigationbar and toolbar?

once again I have a problem with my custom navigation- and toolbar:
I've customised their tintColor and the font by using the appearance proxy in didFinishLaunchingWithOptions. Initially the bars should be hidden by setting their center outside the visible area in viewDidLoad. By single-tapping I use my own animation to slide the bars in/out. Everything was working just fine until the next step:
I wanted the UIBarButtonItems to have the same font like i used in the bars, so I went back to didFinishLaunchingWithOptions and added the following code:
[[UIBarButtonItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:FONT_HEADER size:0.0],UITextAttributeFont,nil] forState:UIControlStateNormal];
It works just fine for the font part, but somehow it also sets the bars back into the visible position before viewWillAppear so the bars are not initially hidden anymore. I tried to find out what causes this unmeant repositioning and couldn't find any connection. I also tried to reset the position at some later point like viewWillAppear but this somehow doesn't work for the toolbar.
EDIT: The described behaviour does only occur on devices with iOS 5 though. On the iOS6 simulator everything still seems fine.
Does anyone have a hint for me what is going wrong here or how I could smoothly solve this problem?
Thanks in advance
[[UIBarButtonItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:FONT_HEADER size:0.0],UITextAttributeFont,nil] forState:UIControlStateNormal];
what's the FONT_HEADER here? Did you check if the ios 5 support this font?

How to change border color of UIPopoverController? [duplicate]

I'm working on an iPad application and I'm using UIPopoverControllers. I'm at the part where the app needs to be branded and styled and i'm wondering how to change the color / tint of the UIPopoverController? Standard is dark blue but it needs to be another color..
is this possible?
Greets, Thomas
This is possible starting in iOS 5.0 by subclassing the abstract class UIPopoverBackgroundView and assigning your subclass to the popoverBackgroundViewClass property on your UIPopoverController instance. Unfortunately there is no tintColor property as the popover needs to use images for it's arrow and border in order to achieve smooth animations during dynamic resizing. You can learn more about how to customize the appearance of a UIPopoverController in the UIPopoverBackgroundView Class Reference
It's impossible for now.
It's what I call the "Box in a Box" model. You get control of the box inside of the box (the UIViewController inside of the UIPopoverController), but you have very limited control over the actual popover itself. Outside of the arrow direction and the size, you can't change much else. There are also options for a modal effect popover, which dims everything else when it shows up, but I haven't tried to get it working.
I'm sure you've noticed there is no UIPopover class by now.
The answer you want to hear:
If you really want to style one that bad, just write your own. It's really not that hard.
The link you want to click:
Cocoacontrols is an index of iOS and OSX components available on GitHub, they have some popover stuff.
iOS 7 introduces backgroundColor property of UIPopoverController which affects/includes the navigation background color as well as arrows of popover.
#property (nonatomic, copy) UIColor *backgroundColor NS_AVAILABLE_IOS(7_0);
Usage example:
if ([self.popoverVC respondsToSelector:#selector(setBackgroundColor:)]) { // Check to avoid app crash prior to iOS 7
self.popoverVC.backgroundColor = [UIColor greenColor]; // [UIColor colorWithPatternImage:#"..."] doesn't reflect the color on simulator but on device it works!
}
Note - As of now (iOS 7.0.3), in some cases (like set color using colorWithPatternImage:), the simulator (and even some devices) doesn't honor the color.
Throwing my hat in here;
I've leveraged UIPopoverBackgroundViews in iOS 5+ to add a simple tintColor property onto UIPopoverControllers.
PCPopoverController: https://github.com/pcperini/PCPopoverController
I try to trick it by customizing the view controller inside the popover and then hiding the popover border using this code:
UIView * border = [[insideViewController.view.superview.superview.superview subviews] objectAtIndex:0];
border.hidden = YES;
The app is actually still in development so I'm hoping other people will comment on this solution.
check out these latest projects leveraging UIPopoverBackgroundView
https://github.com/CRedit360/C360PopoverBackgroundView
https://github.com/GiK/GIKPopoverBackgroundView
from ios 5 onward it is can be done, here is a library
https://github.com/ddebin/DDPopoverBackgroundView
just look at the documentation , and it is quite easy
good luck
You can use Elegant Popover cocoapod for just that. You can customise shape and colour of the arrow and the popover itself. Also, you can add colourful borders to the popover.
I know this is a lousy constructed answer, but I've just been playing with the UIPopoverController's views. They do exist.
The only way to access them is from your view that is sitting in the UIPopovercontroller.
I have a navigation controller so I follow this hierarchy
UIView *test = ((UIView *)[[[self.navigationController.view.superview.superview.subviews objectAtIndex:0] subviews] objectAtIndex:1]);
UIView *test2 = ((UIView *)[[[self.navigationController.view.superview.superview.subviews objectAtIndex:0] subviews] objectAtIndex:1]);
test.backgroundColor = [UIColor greenColor];
test2.backgroundColor = [UIColor greenColor];
This isn't exactly the end goal, but it is really close.
you'll find that the_view_in_the_popover.superview.superview (maybe just one superview if you are not reaching out from a navigation controller view) is a UIPopoverView. If you cast it as a UIView and treat it as a UIView you're not really breaking any rules. I guess that is really up to apple though.
Remove UIPopoverController border:
NSArray* subviews = ((UIView*)[popupController.contentViewController.view.superview.superview.superview.subviews objectAtIndex:0]).subviews;
for(UIView *subview in subviews){
[subview removeFromSuperview];
}

Resources