Center vertically in UILabel with autoshrink - ios

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;

Related

UILabel sizeThatFits too wide for 1-line label

I have a label that I'm creating and displaying programmatically. It can be 1 or more lines. I want to the label to be truncated at the end if it's too long. When the label is > 1 line long the following code works fine. Create a blank project and drop this into viewDidLoad to play along at home. Any iOS or tvOS project should do.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.numberOfLines = 2;
label.lineBreakMode = NSLineBreakByTruncatingTail;
label.backgroundColor = [UIColor blueColor];
[self.view addSubview:label];
NSDictionary *attributes = #{NSFontAttributeName:[UIFont systemFontOfSize:26.0]};
label.attributedText = [[NSAttributedString alloc] initWithString:#"The rain in Spain falls mainly on the plain." attributes:attributes];
CGSize maxLabelSize = CGSizeMake(200, CGFLOAT_MAX);
CGSize requiredSize = [label sizeThatFits:maxLabelSize];
NSLog(#"requiredSize: %#", NSStringFromCGSize(requiredSize));
label.frame = CGRectMake(50.0, 50.0, requiredSize.width, requiredSize.height);
However, if I change numberOfLines to 1 then sizeThatFits returns a size with a width wide enough to fit the entire string even though it's bigger than the width of maxLabelSize.
I can work around this by checking to see if requiredSize.width is greater than maxLabelSize.width, and adjusting appropriately, but I'd like to know why sizeThatFits behaves differently with a 1-line label than with a multi-line label. I would expect a size no greater than 200 with the height the same as the attributed string's line height.
I have no idea why sizeThatFits doesn't work, but another method textRectForBounds:limitedToNumberOfLines: does the trick. Something like
label.numberOfLines = 0;
CGSize requiredSize = [label textRectForBounds:CGRectMake(0, 0, 200, CGFLOAT_MAX) limitedToNumberOfLines:1].size;
UILabel * commlbl;
commlbl=[[UILabel alloc]initWithFrame:CGRectMake(10, commlbl1.bounds.size.height+50, commscroll.bounds.size.width-25, commscroll.bounds.size.height+70)];
[commlbl setFont:[UIFont fontWithName:#"OpenSans-Regular" size:16]];
[commlbl setTextColor:[UIColor whiteColor]];
[commlbl setTextAlignment:NSTextAlignmentCenter];
commlbl.lineBreakMode = NSLineBreakByWordWrapping;
commlbl.numberOfLines = 0;
commlbl.text = [USER_DFT GetUserDefault:#"msgString"];
CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX);
CGSize expectedLabelSize = [commlbl.text sizeWithFont:commlbl.font constrainedToSize:maximumLabelSize lineBreakMode:commlbl.lineBreakMode];
//adjust the label the the new height.
CGRect newFrame = commlbl.frame;
newFrame.size.height = expectedLabelSize.height;
commlbl.frame = newFrame;

Trouble positioning custom navigationItem titleView

I have a custom view (titleView) that I've created for a webView on my iOS app. The titleView has two labels, a titleLabel and a subTitleLabel. If the titleLabel is too wide for the titleView, I truncate the text and have it fill the whole frame. But the problem happens whenever the titleLabel is smaller that the titleView. I get inconsistent results when I try to calculate the position of the titleLabel's frame. I just assumed I would take the difference between the width of the titelView.frame.size.width and the titleLabel.frame.size.widthand divide that by 2, but it doesn't work. I'm probably missing something stupid, but I just can't see it. One thing to note is that the subTitleLabel's seem to be positioned fairly well, and though it's not perfect, it's better than the titleLabel's.
Here are some images (I added borders to the titleView and it's subViews to help show positioning) that show positioning with various length title strings:
Code:
UIView *titleView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width - 88, 34)];
titleView.clipsToBounds = YES;
UIFont *titleFont = [UIFont systemFontOfSize:16 weight:UIFontWeightThin];
UIFont *speakerFont = [UIFont systemFontOfSize:10 weight:UIFontWeightLight];
CGSize speakerSize = [[self.speech speakerFullNameAndDate] sizeWithAttributes:#{ NSFontAttributeName : speakerFont }];
CGSize titleSize = [self.speech.title sizeWithAttributes:#{ NSFontAttributeName : titleFont }];
UILabel *titleLabel = [[UILabel alloc] init];
UILabel *subTitleLabel = [[UILabel alloc] init];
[titleView addSubview: titleLabel];
[titleView addSubview:subTitleLabel];
CGFloat titleDifference = (titleView.frame.size.width - titleLabel.frame.size.width) / 2;
titleLabel.text = self.speech.title;
titleLabel.font = titleFont;
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.textColor = [UIColor whiteColor];
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
// titleLabel is bigger than the titleView's frame
if (titleSize.width > titleView.frame.size.width) {
titleLabel.frame = CGRectMake(0, 0, titleView.frame.size.width - 20, 18);
} else {
// titleDifference / 3 seems to be the best number for the frame's x coordinate
titleLabel.frame = CGRectMake(titleDifference / 3, 0, titleSize.width, 18);
[titleLabel sizeToFit];
}
subTitleLabel.text = [self.speech speakerFullNameAndDate];
subTitleLabel.font = speakerFont;
subTitleLabel.textAlignment = NSTextAlignmentCenter;
subTitleLabel.textColor = [UIColor whiteColor];
subTitleLabel.backgroundColor = [UIColor clearColor];
// Again, ((titleView.frame.size.width - speakerSize.width) / 3) seems to work best, though it's far from perfect
subTitleLabel.frame = CGRectMake(((titleView.frame.size.width - speakerSize.width) / 3), 20, speakerSize.width, 12);
[subTitleLabel sizeToFit];
self.navigationItem.titleView = titleView;
You are calculating your title label origin wrong remember that any view origin is the top left corner, so your title label origin should be something like
CGFloat originX = titelView.frame.size.width/2 - titleLabel.frame.size.width/2
what you are doing is assuming a view origin is in the center of the view

Issue with vertical scrolling in UIScrollView

I am using following code to create my view.
self.percentage_ans_view = [[UIView alloc] init];
float height = 0.0f;
for (int i=0; i < answer_set.count; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20,height ,280,50 )];
[label setText: [self.answer_set objectAtIndex:i]];
[label setTextAlignment:NSTextAlignmentLeft];
[label setBackgroundColor:[UIColor clearColor]];
label.textColor = [UIColor colorWithRed:0.2941f green:0.4666f blue:0.9549f alpha:1.0f];
label.lineBreakMode = NSLineBreakByWordWrapping;
label.numberOfLines = 0;
[label sizeToFit];
// label.tag = 5000 + i;
label.userInteractionEnabled = YES;
label.font = [UIFont fontWithName:#"Arial" size:14.0f] ;
[self.percentage_ans_view addSubview:label];
height += label.frame.size.height;
NSLog(#"LABEL SIZE height : %f & width : %f",label.frame.size.height,label.frame.size.height);
NSLog(#"ans:%#", [self.answer_set objectAtIndex:i]);
UIButton *ans_btn = [UIButton buttonWithType:UIButtonTypeCustom];
ans_btn.frame = CGRectMake(0 - 5, height, (width * 3)+ 20,40 );//CGRectMake(0 - 5, 45 + (i * 80), (width * 3)+ 20,40 )
[ans_btn setTitle:[NSString stringWithFormat:#"%d%#",percent,#"% "] forState:UIControlStateNormal];
ans_btn.titleLabel.font = [UIFont boldSystemFontOfSize:20];
ans_btn.titleLabel.textColor = [UIColor whiteColor];
ans_btn.backgroundColor = [UIColor colorWithRed:0.2941f green:0.4666f blue:0.9549f alpha:1.0f] ;
// ans_btn.frame = frame; your desired size
ans_btn.clipsToBounds = YES;
height += ans_btn.frame.size.height;
[self.percentage_ans_view addSubview:ans_btn];
}
[self.swipe addSubview:self.percentage_ans_view];
Here self.swipe is UIScrollView which is not scrolling vertically. So i am not able to see last two labels and button of my view. What i am doing wrong ?
Set the contentSize property of your UIScrollView properly (basically the width/height of the content that can be displayed in the scroll view without scrolling), set the pagingEnabled property of the scroll view to YES, and then add your view that you want to scroll as a subview of the UIScrollView.
As long as the lenght of the subview is more than the width of the contentSize you specified, it should scroll vertically.
If this scrollView is an IBOutlet, check if the autolayout is disabled for the parent view.
If you are using auto layout, you should add constrains to the scrollViews subviews, that will fully specify it's contentSize.

Resize text in a UILabel (subview of UITableViewCell) to fit width

I have a UITableViewCell that is customized, sometime, text in UILabel (UILabel is subview in UITableViewCell) is exceeds size, and it get some dots (like ...) in label.
I want to adjust font size to fit width. But it does not work.
Here is my code
In Class implement for UITableviewCell
-(void) awakeFromNib{
myLabel.minimumFontSize = 8;
myLabel.adjustsFontSizeToFitWidth = YES;
}
Please help me!!!
Try this simple code
UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
label.backgroundColor=[UIColor clearColor];
label.text= yourString;
label.numberOfLines=0;
label.adjustsFontSizeToFitWidth=YES;
label.minimumFontSize=6;
label.textAlignment=UITextAlignmentCenter;
[self.View addSubview:label];
CGFloat fontSize = 20;
while (fontSize > 0.0)
{
CGSize size = [yourString sizeWithFont:[UIFont fontWithName:#"Rockwell-Bold" size:fontSize] constrainedToSize:CGSizeMake(label.frame.size.width, 10000) lineBreakMode:UILineBreakModeWordWrap];
if (size.height <= label.frame.size.height) break;
fontSize -= 1.0;
}
//set font size
label.font = [UIFont fontWithName:#"Rockwell-Bold" size:fontSize];
[label release];
try this one...
myLabel.numberOfLines=0;
[myLabel sizeToFit];
at First. In your TableViewClass, in heightForRowAtIndexPath you have to calculate the height of your text according to your label and return it.
and make your label's autoLayout property flexible height. You do not need to reset your label's frame. try this it will work....

Changing an embedded UITextView width on rotation?

I have a UITextView embedded inside a grouped table view cell that I can't seem to update on rotation. It basically keeps the same width (assumed portrait) when it becomes landscape, causing about 40% of the view to be blank on the left side.
Is there a way to update this easily? I was looking at willRotateToInterfaceOrientation but I wasn't sure if that was the right thing to update the view on rotation.
Specifically, I'm thinking the width value should be updated, since it's based on the width.
if (indexPath.section == 1) {
switch (indexPath.row) {
case 0:
{
NSString *label = [self.pedal detail];
CGFloat width = [UIScreen mainScreen].bounds.size.width * .95;
CGSize stringSize = [label sizeWithFont:[UIFont systemFontOfSize:15]
constrainedToSize:CGSizeMake(320, 9999)
lineBreakMode:UILineBreakModeWordWrap];
UITextView *textField = [[UITextView alloc] init];
[textField setFrame:CGRectMake(50,0, width-10, stringSize.height+55)];
[textField setEditable:NO];
textField.backgroundColor = [UIColor clearColor];
textField.font = [UIFont systemFontOfSize:15];
textField.textAlignment = UITextAlignmentLeft;
cell.accessoryView = textField;
textField.text = [self.pedal detail];
[textField release];
break;
}
}
}
You need to set textField.autoresizingMask = UIViewAutoresizingFlexibleWidth, which streches the object on its width on view size change.
Read more at the UIView documentation
You have tried setting the sizing properties in IB right? The way the object scales and what points are anchors should be able to be set there.

Resources