How to fix UILabel text spacing? - ios

This code worked fine on iOS 12 and under and the issue occurs when running iOS 13. The goal is to remove the line height spacing to 0 so my labels have a reduced amount of space in between text. I have two labels inside a collection view cell and when I scroll the cells off the screen and then scroll back down the label text is now "cut off". This was not the case as I mentioned in previous versions of iOS. Any help fixing this would be amazing. Thanks ahead of time.
This is my code:
extension: UILabel {
func addLineSpacing(spacing: CGFloat) {
guard let text = text else { return }
let originalText = NSMutableAttributedString(string: text)
let style = NSMutableParagraphStyle()
let lineHeight = font.pointSize - font.ascender + font.capHeight
let offset = font.capHeight - font.ascender
let range = NSRange(location: 0, length: text.count)
style.maximumLineHeight = lineHeight
style.minimumLineHeight = lineHeight
style.alignment = .center
originalText.addAttribute(.paragraphStyle, value: style, range: range)
originalText.addAttribute(.baselineOffset, value: offset, range: range)
attributedText = originalText
}
}
This is how the UILabel text looks like before scrolling:
This is how it looks after scrolling. Notice how the text seems to be shifted up and cut off

I had the similar issue with UILabel and I fixed it with in following way:
style.maximumLineHeight = lineHeight
style.minimumLineHeight = lineHeight - 0.0001
I know that's not the most beautiful solution and this just a workaround but it's working. Hope it help.

Related

Swift changing line spacing leaves bottom white space

I am trying to change the line spacing for a label to reduce the line space in Arabic language it is too much. The extension function I used from here with additions for Arabic styling is working on controlling the line spacing of the label but the only problem it leaves bottom margin white space I assume equals the same label size before reducing the line space.
The extension function here:
extension UILabel {
// Pass value for any one of both parameters and see result
func setLineSpacing(lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {
guard let labelText = self.text else { return }
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpacing
paragraphStyle.lineHeightMultiple = lineHeightMultiple
paragraphStyle.alignment = .justified
paragraphStyle.baseWritingDirection = .rightToLeft
let attributedString:NSMutableAttributedString
if let labelattributedText = self.attributedText {
attributedString = NSMutableAttributedString(attributedString: labelattributedText)
} else {
attributedString = NSMutableAttributedString(string: labelText)
}
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
self.attributedText = attributedString
}
}
then I just call the function like this:
bodyLabel.attributedText = entry.attributedText
bodyLabel.setLineSpacing(lineSpacing: -20)
I tried the extension it's working fine like this:
bodyLabel.attributedText = entry.attributedText
bodyLabel.setLineSpacing(lineSpacing: -20)
bodyLabel.sizeToFit()
Also if that didn't work check the height for the label, and try setting the content to Fill.
bodyLabel.contentMode = .scaleAspectFill
Constraints of the bodyLabel must be like,
Adjust the bottom constraint of your label to >=0

Scroll UITextView to specific text

i have a uitextview with large texts and above i have a search field. Anything searched, i would love the uitextview to scroll to that specific text and hightlight. And i need to make sure that the uitextview scrolls in such a way that the searched text stays in the first line
I populated the textview with attributed text with some attributes. What i tried is get the text before the target text and tried to get the size of it adding the exact attributes i added on textview text at the beginning.
made a CGPoint using that height and set the contentOffset of the uitextview. But the textview scrolled no where near the target text. Maybe my approach is wrong as i dont have the width of the textview when setting attributes
My code is :
func goToBla() {
if let string = ayatTextView.text {
if let range = string.range(of: tazweedAyahas[8].text) {
let firstPart = string[string.startIndex..<range.lowerBound]
print("before \(tazweedAyahas[5].text) : ")
print(firstPart)
if let otherStr = firstPart as? NSString {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let size = otherStr.size(withAttributes: [NSAttributedStringKey.paragraphStyle: paragraphStyle,
NSAttributedStringKey.font: UIFont(name: "me_quran", size: 30)
])
let point = CGPoint(x: 0, y: size.height)
ayatTextView.setContentOffset(point, animated: true)
}
}
}
}
Your approach is much more complicated than it needs to be. Use the scrollRangeToVisible method of UITextView.
func goToBla() {
if let string = ayatTextView.text, let range = string.localizedStandardRange(of: tazweedAyahas[8].text) {
let viewRange = NSRange(range, in: string)
ayatTextView.selectedRange = viewRange // optional
ayatTextView.scrollRangeToVisible(viewRange)
}
}
Note the following:
Use localizedStandardRange when searching if you want to ignore diacritics and case, and you want other locale specific search features.
Call selectedRange if you want the matching text selected.
If you want to get the selected range at the top, try something like this instead of calling scrollRangeToVisible:
let rect = ayatTextView.layoutManager.boundingRect(forGlyphRange: viewRange, in: ayatTextView.textContainer)
ayatTextView.contentOffset = CGPoint(x: 0, y: rect.origin.y)

How to add the ellipsis after set the line spacing for UILabel?

I found that UILabel use set the line spacing, he no longer shows the size of the ellipsis even if he is not enough, I would like to know how to add the ellipsis
let message:NSString = "Perhaps you are an average student with average intelligence."
let attributedString = NSMutableAttributedString(string: str as String)
let paragraphStyle = NSMutableParagraphStyle();
paragraphStyle.lineSpacing = 5
attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, message.length))
detailLabel.attributedText = attributedString
Do you mean rounded corners? If you want perfectly rounded corners add
detailLabel.layer.cornerRadius = detailLabel.frame.height / 2

UILabel vertical alignment

In my application i am using ActiveLabelfram Github.
In that case, my label does not show the text in the middle of the UILabel. If i use a normal UILabel it works fine, but when settings it to a ActiveLabel, it gets like this.
(Image is taken in runtime)
I think this is the code to play with the alignment somehow:
/// add line break mode
private func addLineBreak(attrString: NSAttributedString) -> NSMutableAttributedString {
let mutAttrString = NSMutableAttributedString(attributedString: attrString)
var range = NSRange(location: 0, length: 0)
var attributes = mutAttrString.attributesAtIndex(0, effectiveRange: &range)
let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSMutableParagraphStyle ?? NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = NSLineBreakMode.ByWordWrapping
if let lineSpacing = lineSpacing {
paragraphStyle.lineSpacing = CGFloat(lineSpacing)
}
attributes[NSParagraphStyleAttributeName] = paragraphStyle
mutAttrString.setAttributes(attributes, range: range)
return mutAttrString
}
ActiveLabel.swift
ActiveType.swift
Any ideas how i can make it in the middle like this:
(Image is taken from Storyboard)
In ActiveLabel.swift replace the drawTextInRect method with
public override func drawTextInRect(rect: CGRect) {
let range = NSRange(location: 0, length: textStorage.length)
textContainer.size = rect.size
let usedRect = layoutManager.usedRectForTextContainer(textContainer)
let glyphOriginY = (rect.height > usedRect.height) ? rect.origin.y + (rect.height - usedRect.height) / 2 : rect.origin.y
let glyphOrigin = CGPointMake(rect.origin.x, glyphOriginY)
layoutManager.drawBackgroundForGlyphRange(range, atPoint: glyphOrigin)
layoutManager.drawGlyphsForGlyphRange(range, atPoint: glyphOrigin)
}
I have also forked the repo under https://github.com/rishi420/ActiveLabel.swift
If you download the repo, remember to set verticalTextAlignmentCenter to true
Have a look at this post:
Programmatically Add CenterX/CenterY Constraints
Well the problem will be when u have dragged a label already from the IB and then you are trying to change its position. The code will break.
You will need to programmatically make the label and then set it to the centre.
And very seriously, #Alex is correct. AutoLayout solves a lot of problems.
You can set the textAlignment in the code like this:
showLab.textAlignment = NSTextAlignmentCenter;
Or you can also use Storyboard or xib to see what happen in the lab,StoryBoard,as you look i choose the Second of alignment what means middle in the label

How to implement UILabel line spacing using xib?

I want to align a UILabel's text vertically with line spacing via xib in iOS, for example:
hello,
how are
you?
Please help me.
Yes it is possible to adjust line spacing via xib. Click on UIlabel on xib,then change ‘text’ property type to ’Attributed’,then go through following images. Then enter new line(press ctrl-return shortcut key)and keep cursor in between two lines then adjust ‘line’ property and ‘Max Height’ property you want. My UILael text is "Hello,how are you?"
Create this simple UILabel subclass:
#interface CustomLabel : UILabel
#property (assign, nonatomic) CGFloat myLineSpacing;
#end
#implementation CustomLabel
- (void)setMyLineSpacing:(CGFloat)myLineSpacing {
_myLineSpacing = myLineSpacing;
self.text = self.text;
}
- (void)setText:(NSString *)text {
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = _myLineSpacing;
paragraphStyle.alignment = self.textAlignment;
NSDictionary *attributes = #{NSParagraphStyleAttributeName: paragraphStyle};
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text
attributes:attributes];
self.attributedText = attributedText;
}
Set myLineSpacing property value with IB.
Still you cannot preview in IB, but line spacing value is in xib!
You can set label.text in your code without caring about line spacing.
Note:
don't make property name "lineSpacing".
UILabel do have undocumented lineSpacing property, and overriding that breaks something.
*From Interface Builder:**
Programmatically:
SWift 4
Using label extension
extension UILabel {
// Pass value for any one of both parameters and see result
func setLineSpacing(lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {
guard let labelText = self.text else { return }
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpacing
paragraphStyle.lineHeightMultiple = lineHeightMultiple
let attributedString:NSMutableAttributedString
if let labelattributedText = self.attributedText {
attributedString = NSMutableAttributedString(attributedString: labelattributedText)
} else {
attributedString = NSMutableAttributedString(string: labelText)
}
// Line spacing attribute
attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
self.attributedText = attributedString
}
}
Now call extension function
let label = UILabel()
let stringValue = "How\nto\nimplement\nUILabel\nline\nspacing\nusing\nxib?"
// Pass value for any one argument - lineSpacing or lineHeightMultiple
label.setLineSpacing(lineSpacing: 2.0) . // try values 1.0 to 5.0
// or try lineHeightMultiple
//label.setLineSpacing(lineHeightMultiple = 2.0) // try values 0.5 to 2.0
Or using label instance (Just copy & execute this code to see result)
let label = UILabel()
let stringValue = "How\nto\nimplement\nUILabel\nline\nspacing\nusing\nxib?"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
// Line spacing attribute
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
// Character spacing attribute
attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length))
label.attributedText = attrString
Type it exactly the same way you desire in any text editor like TextEdit etc and then paste in the text section of your label in xib.
But make sure height of your label is more to fit the content and also increase the number of lines. For this case it can be 3 or more.

Resources