Text not vertically centered in UILabel - ios

I've created a Label with the following code :
func setupValueLabel() {
valueLabel.numberOfLines = 1
valueLabel.font = UIFont(name: "Avenir-Black", size: 50)
valueLabel.adjustsFontSizeToFitWidth = true
valueLabel.clipsToBounds = true
valueLabel.backgroundColor = UIColor.greenColor()
valueLabel.textColor = valuesColor
valueLabel.textAlignment = NSTextAlignment.Center
}
I don't really understand why but the label is not vertically centered :
Do I have to do anything specific so it can be centered ?

The problem is that font size is shrunk by adjustsFontSizeToFitWidth = true, but it does not adjust the lineHeight automatically. It remains to be for original font size that is 50.
By default, the text is aligned to its baseline. you can adjust it with baselineAdjustment property.
In your case, you should set it to UIBaselineAdjustment.alignCenters.
valueLabel.baselineAdjustment = .alignCenters

Thanks to #rintaro, it works finally.
One more thing for my case, it didn't work because I was setting ByWordWrapping. I had to set lineBreakMode as ByClipping.

Related

Why doesn't adjustsFontSizeToFitWidth work

I create a UILabel like this, but nothing happens, the text does not increase.
my code:
firstLabel = UILabel()
firstLabel.text = "Выберите 2 лица"
firstLabel.textColor = UIColor(alpha: 1, red: 64, green: 156, blue: 255)
firstLabel.textAlignment = .center
firstLabel.numberOfLines = 1
firstLabel.minimumScaleFactor = 0.1
firstLabel.adjustsFontSizeToFitWidth = true
firstLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(firstLabel)
firstLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 3 * widthView/8).isActive = true
firstLabel.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
firstLabel.widthAnchor.constraint(equalToConstant: safeWidthView - 40).isActive = true
adjustsFontSizeToFitWidth will not increase the font size to fill the remaining space in label if the label has bigger width than the actual content size, it is intended to only shrink the font size to appropriate value to accommodate text if text is bigger than than label's bounding rectangle
Quoting apple
Normally, the label draws the text with the font you specify in the
font property. If this property is true, and the text in the text
property exceeds the label’s bounding rectangle, the label reduces the
font size until the text fits or it has scaled the font down to the
minimum font size. The default value for this property is false. If
you change it to true, be sure that you also set an appropriate
minimum font scale by modifying the minimumScaleFactor property. This
autoshrinking behavior is only intended for use with a single-line
label.
Link: https://developer.apple.com/documentation/uikit/uilabel/1620546-adjustsfontsizetofitwidth

Dynamically adjust width of UILabel in Swift 3

I'm trying to get my UILabel to get wider (along with its border and background color) as the content gets more - and then less when the content is reduced.
Where do I go to get started, I've looked at the Attributes Inspectors and it looks like this can only be done with code (which I'm fine with).
I thought adding two labels in a horizontal stack would do the trick, but it doesn't update in real-time (it will update the label only on launch).
Try using :
myLabel.sizeToFit()
on your label.This should update the label's frame to fit the content.
let label:UILabel = UILabel()
label.textColor=UIColor.black
label.font = UIFont(name: "Halvetica", size: 17)
label.numberOfLines = 1
label.text = "your string"
label.sizeToFit()
label.frame = CGRect(x: 5, y: imageView.frame.height+10, width: label.frame.width, height:label.frame.height)

Get The Font Size

I have a multiple UILabels. When the device size changes the width and height of the labels changes, so I scale down the text so it fits inside the label. What I want to do is get the font size from one label, and set it as the font size of the other labels, so that everything fits inside the labels, but are also the same size.
This is my code for rescaling the text:
Name_Label.numberOfLines = 1
Name_Label.adjustsFontSizeToFitWidth = true
Name_Label.lineBreakMode = NSLineBreakMode.ByClipping
I can get the point size as other answers have suggested:
Year_Label.font.fontWithSize(Name_Label.font.pointSize)
But this does not work, and comments suggest that this does not return the font size. So how do I get the font size of a label that has just been scaled down, and use that to set the other labels font size?
UPDATE: When I print the following code the output is the same, however in the simulator the size is different.
Year_Label.font = Name_Label.font
You can use this class to fit labels size. Just tell that your label is this class. There you as well can set if it should check horizontally or vertically.
https://github.com/VolodymyrKhmil/BBBLibs/tree/master/BBBAutoresizedFontLabel
Hope it helps.
After doing more research, I found a function in Swift 3 that worked. However, to change the size you have to set the Minimum Font Scale (Which I forgot to do). Below is the code in Swift 2 that works:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
Name_Label.numberOfLines = 1
Name_Label.adjustsFontSizeToFitWidth = true
Name_Label.lineBreakMode = NSLineBreakMode.ByClipping
func adjustedFontSizeForLabel(label: UILabel) -> CGFloat {
let text: NSMutableAttributedString = NSMutableAttributedString(attributedString: label.attributedText!)
text.setAttributes([NSFontAttributeName: label.font], range: NSMakeRange(0, text.length))
let context: NSStringDrawingContext = NSStringDrawingContext()
context.minimumScaleFactor = label.minimumScaleFactor
text.boundingRectWithSize(label.frame.size, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: context)
let adjustedFontSize: CGFloat = label.font.pointSize * context.actualScaleFactor
return adjustedFontSize
}
Name_Label.font = Name_Label.font.fontWithSize(adjustedFontSizeForLabel(Name_Label))
Year_Label.font = Year_Label.font.fontWithSize(adjustedFontSizeForLabel(Name_Label))
House_Label.font = House_Label.font.fontWithSize(adjustedFontSizeForLabel(Name_Label))
}
Link to source: https://stackoverflow.com/a/38568278/6421669

Adjust font size of text to fit in UIButton

I want to make sure the button text fits into a UIButton, while the UIButton has a fixed size.
Of course I can access the titleLabel of the UIButton.
In a label I would set autoshrink to minimum font scale which seems to correspond to
self.myButton.titleLabel.adjustsFontSizeToFitWidth = YES;
, but doesn't really behave the same, since it only makes the text fits horizontally into the bounds, not vertically, thereby not changing the font size.
How can i actually adjust the font size of a label programmatically to make the text fit into the label bounds (as shown in Goal in the picture below) ?
I already tried
self.myButton.titleLabel.numberOfLines = 0;
self.myButton.titleLabel.minimumScaleFactor = 0.5f;
without success, always ended up as in adjustsFontSizeToFitWidth on the left side of the pic above.
Edit: The solution also has to be ios7 compliant
self.mybutton.titleLabel.minimumScaleFactor = 0.5f;
self.mybutton.titleLabel.numberOfLines = 0; <-- Or to desired number of lines
self.mybutton.titleLabel.adjustsFontSizeToFitWidth = YES;
... did the trick, after layoutIfNeeded in viewDidLoad
As it turns out, all those must be set to actually adjust the font-size, not just making it fit into the frame.
Update for Swift 3:
mybutton.titleLabel?.minimumScaleFactor = 0.5
mybutton.titleLabel?.numberOfLines = 0 <-- Or to desired number of lines
mybutton.titleLabel?.adjustsFontSizeToFitWidth = true
Updated code for Swift 3.0:
yourButton.titleLabel?.minimumScaleFactor = 0.5
yourButton.titleLabel?.numberOfLines = 0
yourButton.titleLabel?.adjustsFontSizeToFitWidth = true
You can also set a User Defined Runtime Attribute in Interface Builder for the button where
titleLabel.adjustsFontSizeToFitWidth = true
to make text horizontally and vertically fit with button bounds :
1 - set button alignment like image (* VERY IMPORTANT *)
2 - add this lines of code in your ViewController
btnTest.setTitle("Test for multi line in button show line in button show Test for multi line in button show line in button show", for: .normal)
btnTest.titleLabel!.textAlignment = .center
btnTest.titleLabel!.numberOfLines = 0
btnTest.titleLabel!.adjustsFontSizeToFitWidth = true
btnTest.titleLabel!.minimumScaleFactor = 0.5
// below line to add some inset for text to look better
// you can delete or change that
btnTest.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
note that DON'T using btnTest.titleLabel!.lineBreakMode = NSLineBreakMode.byWordWrapping or other BreakMode in your code . for enable multiline in button . just using from above code
final result :
Try to call the following method.
button.titleLabel?.baselineAdjustment = UIBaselineAdjustment.AlignCenters
try this:
[myButton setFont:[[myButton font] fontWithSize:--originalButtonFontSize]];
textWidth = [text sizeWithFont:[myButton font]].width;
}
In Storyboard, Go to Link Break in Attributes Inspector, see word wrap..or set according to your choice.
In Xcode->Open storyboard->Go to attributes inspector->Control->Alignment->Choose second in both horizontal and vertical.
or
YourButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
If you prefer do in storyboard, just click the button, then show attributes inspector, and set the line break to "Word Wrap".

UITextView lineHeightMultiple Clips Top, first line, of Text

In iOS 8, I have a vanilla UITextView that clips the top of the 1st line when a lineHeightMultiple is applied to it's NSMutableParagraphStyle, see image below:
It appears as though lineHeightMultiple affects the 1st line of text in addition to subsequent lines.
Setting clipsToBounds = false on the UITextView will at least enable the clipped part to show, but you can see from the image below that now the top part of the text is obviously above it's frame:
I can fix this by just setting the top constraint on the offending UITextView to compensate for clipsToBounds = false but that feels like a hack to me.
I have also tried using a WKWebView for the offending text, and just setting the css line-height property, and that works just fine. There must simply be something I am missing when it comes to UITextView though.
Additionally, setting lineSpacing on the paragraph style to less than 0 has no affect, per the docs:
The distance in points between the bottom of one line fragment
and the top of the next.
**This value is always nonnegative.**
This value is included in the line fragment heights in the
layout manager.
I have also tried setting the contentInset of the UITextView as well as using a system font, both had not affect.
My sample code for this setup follows:
let text = "THIS IS A MULTILINE RUN OF TEXT"
let font = UIFont(name: "MyFontName", size: 31.0)!
// let font = UIFont.systemFontOfSize(31.0)
let paragraph = NSMutableParagraphStyle()
paragraph.lineHeightMultiple = 0.75
paragraph.alignment = NSTextAlignment.Center
let attributes = [
NSParagraphStyleAttributeName: paragraph,
NSFontAttributeName: font
]
titleView.attributedText = NSAttributedString(string: text, attributes: attributes)
// titleView.contentInset = UIEdgeInsets(top: 50.0, left: 0.0, bottom: 0.0, right: 0.0)
titleView.clipsToBounds = false
Has anyone encountered this and overcome or is the top constraint hack the only way to go?
I had the same issue.
I compensated it using NSBaselineOffsetAttributeName.
You should use:
let attributes = [
NSParagraphStyleAttributeName: paragraph,
NSFontAttributeName: font,
NSBaselineOffsetAttributeName: -5
]
You will have to also set a lower paragraph.lineHeightMultiple.
A little tricky, but it works.
Cooliopas is right, but I ended up using this in a label extension and needed something more suited for the many different sizes of text throughout my app. I found that the baseline adjustment to keep the text vertically centered was 10% of the height of the text.
let attrString = NSMutableAttributedString(string: newText)
let style = NSMutableParagraphStyle()
style.alignment = self.textAlignment
style.lineSpacing = 1.0
style.lineHeightMultiple = 0.75
var baselineOffset : CGFloat = -5 //-5 is a default for this in case there is no attributedText size to reference
if let size = self.attributedText?.size(){
baselineOffset = size.height * -0.1
} else {
NSLog("attributedText = nil, setting lineHeightMultiple to -5 as a default for ", newText)
}
attrString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSMakeRange(0, attrString.length))
attrString.addAttribute(NSBaselineOffsetAttributeName, value: baselineOffset, range: NSMakeRange(0, attrString.length))
self.clipsToBounds = false
self.attributedText = attrString
Alternative approach - use a stack view with two labels, and set the stack view spacing to the top label's font's descender.

Resources