Center image by first line of UILabel text - ios

I want to center image to center Y position of first line of text of my UILabel. I use masonry to set Auto Layout constraints like that:
[_haveReadIndicatorImgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.equalTo(self.contentView).offset(SMALL_OFFSET);
make.height.width.equalTo(#(8));
}];
[_topTxtlbl mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_haveReadIndicatorImgView.mas_right).offset(TINY_OFFSET);
make.top.equalTo(_haveReadIndicatorImgView.mas_top);
make.right.equalTo(self.arrowImgView.mas_left).offset(-SMALL_OFFSET);
make.bottom.equalTo(_dateTxtLbl.mas_top).offset(-SMALL_OFFSET);
}];
It should be pretty strightforward. I simply attach top of UIImageView to top of my Label.
But take a look at screen.
Top edges of UIImageView (gray dot) and label are equal, but how to make UIImageView to be centered to first line of text like that?
Thanks.

Actually there is a way of doing this! If you use plain old AutoLayout this can be done with the following snippet:
// Aligns the icon to the center of a capital letter in the first line
let offset = label.font.capHeight / 2.0
// Aligns the icon to the center of the whole line, which is different
// than above. Especially with big fonts this makes a visible difference.
let offset = (label.font.ascender + label.font.descender) / 2.0
let constraints: [NSLayoutConstraint] = [
imageView.centerYAnchor.constraint(equalTo: label.firstBaselineAnchor, constant: -offset),
imageView.trailingAnchor.constraint(equalTo: label.leadingAnchor, constant: -10)
]
NSLayoutConstraint.activate(constraints)
The first constraint will display your icon at the Y center of the first line of your label. The second one puts your icon left of the label and creates a 10pt space between them.
Hope this helps!

You derive the middle of the first line by using the lineHeight for the font of your label.
let lineHeight = ceil(multiLineLabel.lineHeight)
let center = lineHeight / 2
Now that you have the center, you can center the haveReadIndicatorImgView's centerYAnchor to the top of your label with a constant: center

I solved this recently by adding a hidden single line label in exactly the same location and font as the multiline one, without a bottom constraint.
Then you can simply align the icon image .centerY to the hidden label's .centerY.

I achieve following by 2 steps:
1) Calculate expected height of label line of text with specific font:
+(CGSize)getSimpleSizeBasedOnFont:(CGFloat)font{
UILabel *lbl = [UILabel new];
lbl.text = #"Simple text";
lbl.font = [UIFont systemFontOfSize:font];
return [lbl.text sizeWithFont:lbl.font
constrainedToSize:lbl.frame.size
lineBreakMode:NSLineBreakByWordWrapping];
}
Then i add constraints to center Y of UIImage View with offset equal to 50% of that height:
CGFloat lblOffs = [Helper getSimpleSizeBasedOnFont:14].height;
[_haveReadIndicatorImgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(_topTxtlbl.mas_top).offset(lblOffs/2);
make.left.equalTo(self.contentView).offset(SMALL_OFFSET);
make.height.width.equalTo(#(8));
}];

I have done this differently.
At first i align my imageView with label by FirstBaseLine.
And then i took an outlet of that LayoutConstraint
I have calculated an offset like below:
let offset = (label.font.capHeight + imageView.frame.size.height) / 2 //your bulleted image
I have discarded that offset from FirstBaseLine constant
firstBaseLineConstraintWithLabel.constant -= offset
Here is the output

Related

Text alignment in UIlabels

I have 2 adjacent labels of same width. label1 text takes only one line. Text for label2 is long,
objective is to show full text in 2 lines,
I am using label.numberOfLines = 2 and adjustsFontSizeToFitWidth = YES;
Now, first line of label2 is not aligned with first line of label1. while labels are still aligned, label2 text is starting with a margin inside label. I wanted label2 text to start from top.
please help me with this.
Fixed:
CGSize originalSize = [label.text sizeWithAttributes:#{NSFontAttributeName:label.font}];
CGFloat usedScaleFactor = label.frame.size.width / originalSize.width;
CGFloat newFontSize = label.font.pointSize * usedScaleFactor;
label.font = [UIFont fontWithName:#"fontName" size:newFontSize];
This fixed my issue. iOS was calculating label frame with my original text font size while changing my text font due to adjustsFontSizeToFitWidth...
Hope this helps someone who is searching this..

Calculate where text starts on centre alignment

I have a UILabel that I want to add a UIView exactly where the text starts.
The problem is that the text in the label is aligned to the centre so I don't know how to determinate where the actual text starts and where to position this UIView.
Any idea how can I calculate this thing?
Thank you!
You can use a UIView container which will wrap the UILabel and your new UIView. Then you can let the UILabel decides the width depending on its content and set it in the center of the container. Once you have this working you can just read the UILabel x to understand where it starts.
so the UILabel will have the constraints to top, bottom, the height you want and at center to horizontal whereas the little UIView to top, bottom, height, width and leading equal to UILabel
From :How to find the position(x,y) of a letter in UILabel
NSRange range = [#"Good,Morning" rangeOfString:#","];
NSString *prefix = [#"Good,Morning" substringToIndex:range.location];
CGSize size = [prefix sizeWithFont:[UIFont systemFontOfSize:18]];
CGPoint p = CGPointMake(size.width, 0);
NSLog(#"p.x: %f",p.x);
NSLog(#"p.y: %f",p.y);
you can modify it for your purpose
you can get text size using "nsattributedstring"
let label = UILabel(frame: CGRectMake(0, 0, 100, 100))
label.text = "dshfk,j"
label.textAlignment = .Center
label.textColor = UIColor.redColor()
let string = label.attributedText
let width = string!.size().width
let height = string!.size().height
let view = UIView(frame: CGRectMake(width, height, width, height))
view.backgroundColor = UIColor.blackColor()
then you can find rect using this ..
sample view
You could also use
yourLabel.sizeToFit()
to automatically resize your label for the space it needs. And then read out the frame of your label with:
yourLabel.frame.size (width or height)

Make background UILabel bigger

I have a question in my app I have a number label (IBOutlet). And when I write self.numberLabel.backgroundColor = [UIColor redColor]; is showing a red color fit in the height of number, All I want is to make the background a little bit bigger. Thanks
self.numberLabel.frame = CGRectMake(self.numberLabel.frame.origin.x, self.numberLabel.frame.origin.y, widht, newHeight);
and to make sure font stay same size if needed
[self.numberLabel setFont:[UIFont systemFontOfSize:35]];
You have to set constraints in Interface Builder / Storyboard to fix your label height/width.
If your label's content changes in width, you can use this to calculate a new width with a bit of space left:
float labelWidth =
[self.myLabel.text
boundingRectWithSize:self.myLabel.frame.size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{ NSFontAttributeName:self.myLabel.font }
context:nil]
.size.width;
CGRect rect = self.myLabel.bounds;
rect.size.width = labelWidth + 15.0f; //replace 15.0F with the value you want
[self.myLabel setBounds:rect];
There're many ways to skin a cat... in my case the content of the "uilabel" determines its size. I just want the background to be slightly bigger -- 5 points vertically, 7 points horizontally. So I use autolayout to solve it.
Add a uilabel as a subview to the background which is a uiview
Add constraints in IB between the uilabel and the uiview
Add constraints in IB between the uiview and its superview

Stretch width of UILabel according to width of containing text with background image

I have the following problem - I need to create two UI labels along side one another as in the screen shot below -
The UI label containing the special offers text is dynamic and needs to adjust to the width of the containing text and also if possible display the slanted orange background with the relevant padding -
I'm predominantly a Front-end dev - so with CSS i'd use a long background image that aligns to the right of the label and pad accordingly - but I have no idea how to approach this in objective C - can anyone offer any advice?
This is not a drop-in solution, but perhaps helps you find it (assuming you don't use Auto Layout):
You need a UIImageView for the background and a UILabel for the text
Use a tileable/strechable image (probably with cap insets) for the background (see [UIImage resizableImageWithCapInsets:resizingMode:])
Set the text on your label
Call [label sizeToFit] to resize the label to exactly fit the contained text
Resize the image view depending on the label's size (e.g. imageView.frame = CGRectInset(label.frame, -10, -10), which would make your image view 10pt larger than the label on all sides).
With Auto Layout you'd just define the appropriate constraints between the label and the image view and rely on the label's "intrinsic content size" - should be quite easy.
You could always shrink the text when it gets to long for the label, go into your view controller, click on the label that you would like to shrink when the text gets too long, then, go down to Autoshrink under Label in the attributes inspector. Change it from fixed font size to minimum font size, then I recommend putting 6 to 8 as the lowest font size. This is going to be the LOWEST font size though, so if XCode can make the label fit while making the font size 9, yet the lowest is 7, it will do it.
Or, you could get the length of the string with
int *stringLength = [myString length]
which counts spaces too, then, change the orange square with
orangeBoxImageView.frame = CGRectMake(0, 0, resizedWidth, resizedHeight);
so you could do something like this with your code:
if(stringLength == 15{
orangeBoxImageView.frame = CGRectMake(0, 0, 15, 5);
}
I hope this could help you
CGFloat rect = [YOURSTRING
boundingRectWithSize: (CGSize){ labelWidth, CGFLOAT_MAX }
options: NSStringDrawingUsesLineFragmentOrigin
attributes: #{ NSFontAttributeName : labelFont };
context: nil];
This assumes numberOfLines = 0.
What you want to use is UILabel -sizeToFit inherited from UIView. You should be able to figure out the rest from there.
Find the size of the containing text with
[text sizeWithFont:font constrainedToSize:CGSizeMake(width, height) lineBreakMode:NSLineBreakModexx]
Once you have that, you can manipulate the size of the label accordingly.
Hope this helps
For the background I'd create a subclass of UILabel that overrides drawInRect:, such as this example that simply draws a rectangle with the size of the label
-(void) drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(c, [UIColor redColor].CGColor);
CGContextFillRect(context, rect);
}
Rather than drawing a rectangle, you should create a path with the shape that you need and fill that. See here for more info:
http://weblog.invasivecode.com/core-graphics
I don't know how you've created your label, but if it's done properly with autolayout it'll have the correct width automagically. See here:
http://www.raywenderlich.com/20881/
Tim

iOS - Get the "real" height of a letter

I am trying to layout text on a UIView.
(The yellow area is the frame of the UILabel with a background color).
When I use sizeWithFont I get this, which has a very large space above the letter:
When I use font.pointSize i get this for "i" which is good-
BUT
When i use it for "p" I get the precise height but the letter is drawn in the bottom and cropped.
**How can i get get the glyph only centered in the frame ? **
Thanks
Shani
There are a lot of properties on UIFont to help in this situation:
pointSize
ascender
descender
capHeight
xHeight
lineHeight
You could convert the UILabel to a UIImage with a "printscreen" sort of function and then check the the pixels one by one (with for instance: How to get pixel data from a UIImage (Cocoa Touch) or CGImage (Core Graphics)?) and 'calculate' the left top en right bottom.
Try moving the text upwards by font.ascender - font.capHeight. Shrinking the height of a UILabel will likely clip its contents, so it is better to adjust the label's y position instead of resizing.
The following code sample explains the computation I used:
// in UILabel subclass:
- (CGFloat) topPadding
{
// ascender = height from baseline to top of label (including top padding)
// capHeight = height of a capital letter = ascender - top padding
// -> top padding = ascender - capHeight
return self.font.ascender - self.font.capHeight;
}

Resources