Set a navigation button for the title of a UINavigationBar - ios

I want to make a standard navigation bar button for my bar's title. I can set a custom view. In the sample below, I've done this with a UILabel. But I don't see how to make a standard navigation button.
-(void) setTitleButtonWithText: (NSString*) text {
self.title = text;
UIFont* font = [UIFont boldSystemFontOfSize:18];
CGSize size = [text sizeWithFont:font];
size.width+=6;
size.height+=6;
UILabel* titleLabel = [[UILabel alloc]init];
CGRect frame = CGRectZero;
frame.size = size;
self.navigationItem.titleView = titleLabel;
titleLabel.frame = frame;
titleLabel.textColor = [UIColor redColor];
titleLabel.text = text;
titleLabel.font = font;
}

titleView is a UIView property, so since UIBarButtonItem is not a UIView it cant be used here, as an alternative you could try making a UIButton with the same style and set that as the titleView

Related

Presenting UIAlertController increases UILabel font size inside UIToolbar in iOS 11

I have an issue with font size of UILabel, which is programmatically added in UIToolbar:
- (UILabel *)createTitleLabel
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(_topToolbar.frame)/3, CGRectGetHeight(_topToolbar.frame))];
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor colorWithWhite:0.1 alpha:1.0];
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont fontWithName:#"ArialMT" size:18];
label.adjustsFontSizeToFitWidth = YES;
label.minimumScaleFactor = 0.8;
label.lineBreakMode = NSLineBreakByTruncatingTail;
return label;
}
// -----
UILabel *label = [self createTitleLabel];
self.titleLabel = label;
[self.topToolbar insertItem:[[UIBarButtonItem alloc] initWithCustomView:label] atIndex:_topToolbar.items.count/2 animated:NO];
// ------ code for adding item to toolbar
- (void)insertItem:(UIBarItem *)barItem atIndex:(NSUInteger)index animated:(BOOL)animated
{
NSMutableArray *toolbarItems = [self.items mutableCopy];
NSAssert(index <= toolbarItems.count, #"Invalid index for toolbar item");
[toolbarItems insertObject:barItem atIndex:index];
[self setItems:toolbarItems animated:animated];
}
After setting a bit large text to title label, it works as expected, font is reduced, and tail is truncated, but when I present UIAlertController, this font is getting larger, and UILabel width is growing, which hides other bar button items inside toolbar.
Beginning with iOS 11, views added to toolbars as UIBarButtonItem using customView initializer are now laid out using auto layout. You should add sizing constraints on your label. For example:
[label.widthAnchor constraintEqualToConstant:CGRectGetWidth(_topToolbar.frame)/3].active = YES;
[label.heightAnchor constraintEqualToConstant:CGRectGetHeight(_topToolbar.frame)].active = YES;
Otherwise, auto layout will use the intrinsic content size of your label which is causing the label.adjustsFontSizeToFitWidth = YES; to be ignored. Sizing likely works initially because adding a bar button item doesn't trigger a layout pass, however presenting and dismissing another view controller will cause auto layout to perform a pass for your view controller's entire view hierarchy.
For more information see the WWDC 2017 session Updating your app for iOS 11.

Adding an Image with a Title in a UINavigationController

I would like to show a small icon next to the title in my UINavigationController.
Through the magic of Photoshop, like this:
I know I need to create a new view and build the image and title into it. Here is what I am doing:
In viewDidLoad in the UINavigationController view controller, I call the method
[self setTitleBar];
Which calls this method:
- (void) setTitleBar {
CGRect navBarFrame = self.navigationController.navigationBar.frame;
//UIView *titleView = [[UIView alloc] initWithFrame:CGRectMake(navBarFrame.origin.x, navBarFrame.origin.y, (leftButtonFrame.origin.x + leftButtonFrame.size.width) - rightButtonFrame.origin.x, navBarFrame.size.height)];
UIView *titleView = [[UIView alloc] initWithFrame:CGRectMake(navBarFrame.origin.x, navBarFrame.origin.y,self.view.frame.size.width,navBarFrame.size.height)];
titleView.backgroundColor = [UIColor clearColor];
CGPoint tvCenter = CGPointMake(titleView.frame.size.width/2, titleView.frame.size.height/2);
UIImage * icon = [UIImage imageNamed:#"star"];
UIImageView *iconView = [[UIImageView alloc] initWithImage:icon];
iconView.frame = CGRectMake(0, 0, icon.size.width, icon.size.height);
UILabel *title = [[UILabel alloc] init];
title.backgroundColor = [UIColor clearColor];
title.textColor = [UIColor whiteColor];
title.textAlignment = NSTextAlignmentCenter;
title.text = #"SOME TITLE";
title.frame = CGRectMake(0, 0, 100, titleView.frame.size.height);
[title sizeToFit];
iconView.center = CGPointMake(tvCenter.x - (icon.size.width/2), tvCenter.y);
[titleView addSubview:iconView];
[titleView addSubview:title];
self.navigationItem.titleView = titleView;
}
My logic in the titleView is: Get the left most button's frame and get the right most buttons frame. THEN do some math to figure out how big the view can be. That should be the titleView's frame size.
However, I can't seem to get it to work. If I plug in a frame size of 0,0,100,40; then it shows the frame but everything is squished together. But you see it. I know that 100 should be dynamic to ensure that the title is shown.
But I can't seem to figure it out.
Any help?
You can place objects on the Navigation Controller View, as subviews.
- (void) setTitleBar {
//Let's say your icon size is 20
int starSize = 20;
//Now you'll have to calculate where to place the ImageView respect the TextSize (for this you'll need to know the text and font of your UINavigationItem title)
CGSize textSize = [#"SOME TITLE" sizeWithAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"navfontname" size:15]}];
UIImageView *startImageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.navigationController.view.frame.size.width/2 - textSize.width/2, self.navigationController.view.frame.size.height/2 - starSize/2, starSize,starSize)];
startImageView.image = [UIImage imageNamed:#"star"];
[self.navigationController.view addSubview:startImageView];
}

Center vertically in UILabel with autoshrink

This is a little different from all the other "How do I center the text in a UILabel" questions here...
I have a UILabel with some text in it, I want to center the text vertically in the UILabel. What's the big deal, right? That's the default. The problem comes because my text is dynamic and I have autoshrink turn on. As the text grows larger, the font size shrinks. You get this behavior.
Notice that the font baseline has not moved, I want it to move so the numbers are centered vertically in the UILabel's frame.
Easy, right? I just remember the frame's original center in viewDidLoad
self.workoutTimeCenter = _workoutTimeLabel.center;
and then I call sizeToFit after I change the the text, right?
[_workoutTimeLabel sizeToFit];
_workoutTimeLabel.center = _workoutTimeCenter;
Well, sizeToFit did, I guess, exactly what it was supposed to do, resize the frame so the text fits without shrinking!
How can I vertically center the text in a UILabel while respecting baselines and autoshrink? (Note, an iOS5 and later solution is fine and I can even deal with an iOS6 and later solution.)
In my experience you can just set the -[UILabel baselineAdjustment] property to UIBaselineAdjustmentAlignCenters to achieve the effect you're describing.
From the docs:
baselineAdjustment
Controls how text baselines are adjusted when text
needs to shrink to fit in the label.
#property(nonatomic) UIBaselineAdjustment baselineAdjustment
Discussion
If the adjustsFontSizeToFitWidth property is set to YES,
this property controls the behavior of the text baselines in
situations where adjustment of the font size is required. The default
value of this property is UIBaselineAdjustmentAlignBaselines. This
property is effective only when the numberOfLines property is set to
1.
and
UIBaselineAdjustmentAlignCenters
Adjust text based relative to the center of its bounding box.
EDIT: adding a full view-controller that demonstrates this:
#interface TSViewController : UIViewController
#end
#implementation TSViewController
- (void) addLabelWithFrame: (CGRect) f baselineAdjustment: (UIBaselineAdjustment) bla
{
UILabel* label = [[UILabel alloc] initWithFrame: f];
label.baselineAdjustment = bla;
label.adjustsFontSizeToFitWidth = YES;
label.font = [UIFont fontWithName: #"Courier" size: 200];
label.text = #"00";
label.textAlignment = NSTextAlignmentCenter;
label.backgroundColor = [UIColor lightGrayColor];
label.userInteractionEnabled = YES;
[self.view addSubview: label];
UIView* centerline = [[UIView alloc] initWithFrame: CGRectMake(f.origin.x, f.origin.y+(f.size.height/2.0), f.size.width, 1)];
centerline.backgroundColor = [UIColor redColor];
[self.view addSubview: centerline];
UITapGestureRecognizer* tgr = [[UITapGestureRecognizer alloc] initWithTarget: self action: #selector(onTap:)];
[label addGestureRecognizer: tgr];
}
- (void) viewDidLoad
{
[super viewDidLoad];
[self addLabelWithFrame: CGRectMake(0, 0, 320, 200)
baselineAdjustment: UIBaselineAdjustmentAlignCenters];
[self addLabelWithFrame: CGRectMake(0, 220, 320, 200)
baselineAdjustment: UIBaselineAdjustmentAlignBaselines];
}
- (void) onTap: (UITapGestureRecognizer*) tgr
{
UILabel* label = (UILabel*)tgr.view;
NSString* t = [label.text stringByAppendingString: #":00"];
label.text = t;
}
#end
when working in IB, be sure to set align baselines to center
Note: line break CANNOT be word wrap for this to work, so it will NOT work multiline (good to set the line break to Truncate tail)
-(void)fitVerticallyToLabel:(UILabel *)lbl
{
CGFloat fontSize = lbl.frame.size.width / lbl.text.length;
[lbl setFont:[UIFont fontWithName:#"Helvetica-Bold" size:fontSize]];
CGRect rect = lbl.frame;
rect.origin.y += rect.size.height - fontSize;
rect.size.height = fontSize;
[lbl setFrame:rect];
}
How to Use: Call this method after setting the text to your label.
label.text = #"text";
[self fitVerticallyToLabel:label];
Note: I ahev taken UILabel from xib. You can take it programmatically too in that case you will have to set its text alignment NSTextAlignMentCenter
Try to implement this logic:
-(void)adjustLabel1Text1:(NSString *)text1
{
UILabel *lbl_first = [UIFont fontWithName:#"Helvetica" size:12];
text1 = [text1 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
float hedingLblHeight = [self calculateHeightOfTextFromWidth:text1 : [UIFont fontWithName:#"Helvetica" size:12] :118 :UILineBreakModeWordWrap];
lbl_first.text=text1;
[lbl_first setFrame:CGRectMake(lbl_first.frame.origin.x, lbl_first.frame.origin.y, 118, hedingLblHeight)];
lbl_first.lineBreakMode = UILineBreakModeWordWrap;
lbl_first.numberOfLines = 0;
[lbl_first sizeToFit];
//////////Adjust the lable or any UIControl below this label accordingly.
float endResultHeight=[self calculateHeightOfTextFromWidth:text2 : [UIFont fontWithName:#"Helvetica" size:15] :299 :UILineBreakModeWordWrap];
if(hedingLblHeight>secondImgTitleHeight)
{
[lbl_endResult setFrame:CGRectMake(lbl_endResult.frame.origin.x, lbl_first.frame.origin.y+lbl_first.frame.size.height+5, 299, endResultHeight)];
}
else
{
[lbl_endResult setFrame:CGRectMake(lbl_endResult.frame.origin.x, lbl_first.frame.origin.y+lbl_first.frame.size.height+5, 299, endResultHeight)];
}
lbl_endResult.lineBreakMode=UILineBreakModeWordWrap;
lbl_endResult.numberOfLines = 0;
[lbl_endResult sizeToFit];
}
-(float) calculateHeightOfTextFromWidth:(NSString*)text : (UIFont*) withFont:(float)width :(UILineBreakMode)lineBreakMode
{
CGSize suggestedSize = [text sizeWithFont:withFont constrainedToSize:CGSizeMake(width, FLT_MAX) lineBreakMode:lineBreakMode];
return suggestedSize.height;
}
It has helped me a lot.Hope it works for you.
Try
yourLabel.textAlignment = UITextAlignmentCenter;

Adjust font size in Navigation Title

Is there any way to make the font of the title of the navigation bar adjusted with the width?
Same behaviour as a [UILabel setAdjustsFontSizeToFitWidth:YES].
I'm trying setting the appearance of the NavigationBar, but no success so far.
Try doing something like:
self.navigationItem.titleView = titleLabel;
where titleLabel is a custom UILabel that you've initialized and customized.
Check out this Fontful code, for example.
There's no way to do this with the standard title item. You can still add your custom UILabel to the navigation bar and take care of the title changes.
You can not change the font of title.
Instead try out this..
self.title = #"My title is this.";
CGRect frame = CGRectMake(0, 0, [self.title sizeWithFont:[UIFont boldSystemFontOfSize:20.0]].width, 44);
UILabel *label = [[UILabel alloc] initWithFrame:frame];
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:17.0];
label.textAlignment = UITextAlignmentCenter;
self.navigationItem.titleView = label;
label.text = self.title;
[label release];

UITableView controller removes custom NavBar TitleView

I have a bit of code that allows me to customize the Navigation Bar title of a view to allow for shrinking / truncating of long titles. The code works fine almost everywhere, however when it's used in a UITableViewController, the title never appears.
The code in question is:
- (void)viewDidLoad
{
[super viewDidLoad];
//Nav bar title for truncating longer titles
CGRect frame = CGRectMake(0, 0, 400, 44);
UILabel *label = [[UILabel alloc] initWithFrame:frame];
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:20.0];
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor whiteColor];
label.adjustsFontSizeToFitWidth = YES;
label.minimumFontSize = 10.0f;
label.lineBreakMode = UILineBreakModeTailTruncation;
label.text = #"This is a really long title. It will shrink and eventually get truncated correctly.";
self.navigationItem.titleView = label;
}
I've put together a small demo project that illustrates the problem.
https://sites.google.com/site/coffeestainit/files/NavTitleError.zip
I just went through your project. The problem is that in your storyboard, you have not connected your tableViewController to the FirstViewController. So the viewDidLoad of the
FirstViewController is never called.
When I set the custom class of your TableViewController to FirstViewController in the storyboard, it set the label as title, as expected

Resources