Calculate where text starts on centre alignment - ios

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)

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..

clipsToBounds on UILabel not working

I have a UILabel, that I am setting up like this:
class someSuperclass {
var firstLetterLabel = UILabel(frame: CGRect(x: 58, y: 0, width: 81, height: 120))
func commonInit() {
firstLetterLabel.font = UIFont(name: "MuseoSans-500", size: 110.0)
firstLetterLabel.textColor = UIColor.museumRed
firstLetterLabel.textAlignment = .center
firstLetterLabel.numberOfLines = 1
firstLetterLabel.lineBreakMode = .byClipping
firstLetterLabel.clipsToBounds = false
addSubview(firstLetterLabel)
}
}
But it is still being clipped by its bounds
Since clipsToBounds does not seem to apply to the content of a label. How can I stop label content from being clipped by it's frame/bounds?
ClipsToBounds allows subviews or sub layers to spill out of a view or prevent that but it does not do that for drawn content by a view and in this case it is a UILabel. You cannot draw past the bounds of the view/label. That is why it is clipped. This difference always clips drawn content.
possible solutions
1) let intrinsic size of the single letter labels keep it from clipping. Place all the the labels in a horizontal stack view.
2) enable minimum font scale on the label to allow it to fit.
3) lastly it appears it is not drawing centered. Not really sure why as you have given very little to look at.
You can use UIButton instead, and setting button.userInteractionEnabled = false.

Center image by first line of UILabel text

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

Resizing the height of UILabel to fit text

I have UILabel in my Cell Subclass which is suppose to hold a title. The size of the title can be various lengths and therefor I need to resize the UILabel to fit the text and to prevent that the text is not to long I also need to be able to set maxHeight. The width should be the same. How can I create such code in swift in a tableViewCell subclass?
So far I have this in awakeFromNib
theTitleLabel?.font = UIFont(name: "HelveticaNeue", size: 13)
theTitleLabel?.textColor = UIColor(rgba: "#4F4E4F")
theTitleLabel?.numberOfLines = 0
theTitleLabel?.lineBreakMode = NSLineBreakMode.ByTruncatingTail
CGSize maximumLabelSize = CGSizeMake(MAX_WIDTH, MAX_HEIGHT);
CGSize expectedSize = [lbl sizeThatFits:maximumLabelSize];
CGSize s = CGSizeMake(STATIC_WIDTH, expectedSize.height);
yourLabel.frame = CGRectMake(yourLabel.frame.origin.x, nameLbl.frame.origin.y, s.width, s.height);
The easiest way to do that is using autolayout constraints. You are using awakeFromNib, so I assume you have that cell somewhere in your Interface Builder (xib or storyboard file).
If you can avoid it, never set up your views in your code. It's far easier to do it in the Interface Builder.
Find your label and set up its attributes (font, color, line break mode etc.) in the Interface Builder.
Add a width constraint (or constraints to left and right margins, depending on what you want).
Add a height constraint, change its relation from = (equals) to < (less than).
You are done, no code is needed.
Swift 2 version, from Zigglzworth's answer :
let maximumLabelSize = CGSizeMake(maxWidth, maxHeight);
let expectedSize = theLabel.sizeThatFits(maximumLabelSize)
theLabel.frame = CGRectMake(theLabel.frame.origin.x, theLabel.frame.origin.y, expectedSize.width, expectedSize.height)
let lblMassage = UILable()
lblMassage.text ="Resizing the height of UILabel to fit text.................."
lblMassage.numberOfLines = 0
lblMassage.lineBreakMode = NSLineBreakMode.byTruncatingTail
lblMassage.preferredMaxLayoutWidth = 190
lblMassage.sizeToFit()

fading scrollMenu with labels

i've created a paged UIScrollView which contains labels on every page. How can i lower the margin between the labels like in the picture and then still being able to scroll?
At the moment my navigationBar look like following. Where u can swipe to next page to the right and get the next label.
What i want is something like this with a small margin and still being able to swipe.
viewDidLoad code
//Category ScrollView
categoryScrollView = UIScrollView(frame: CGRectMake(0, self.navigationController!.navigationBar.frame.height-38, self.view.frame.width, 38))
categoryScrollView?.contentSize = CGSizeMake(self.view.frame.width, 38)
categoryScrollView?.delegate = self
categoryScrollView?.pagingEnabled = true
self.navigationController?.navigationBar.addSubview(categoryScrollView!)
categoryArray = NSArray(objects: "Book", "Elektronik")
var textWidth = 0
for val in categoryArray!
{
var textLabel: UILabel = UILabel()
textLabel.textAlignment = NSTextAlignment.Center
textLabel.text = val as NSString
textLabel.frame = CGRectMake(CGFloat(textWidth), 0, categoryScrollView!.frame.width, categoryScrollView!.frame.height)
categoryScrollView?.addSubview(textLabel)
textWidth = textWidth + Int(textLabel.frame.size.width)
if textWidth > Int(self.view.frame.width) {
categoryScrollView?.contentSize = CGSizeMake(CGFloat(textWidth), categoryScrollView!.frame.height);
}
}
The default width of the "page" when pagingEnabled is switched on is the width of the scroll view. You could reduce the width and let the contained views be visible beyond the edges of the view by setting clipsToBounds to false.
If this does not work for you there also the option to adjust the paging width by intercepting the end of the drag via the UIScrollViewDelegate method scrollViewWillEndDragging(...) where you can adjust the targetContentOffset to fit your needs (see an example here).

Resources