UITextView.attributedText, How to set numberOflines and lineBreakMode? - ios

In some condition I have to use UITextView instead of UILabel(To make link attributes clickable).
Here is my code:
let attributedString = NSMutableAttributedString(string: "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest")
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byTruncatingTail
attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedString.length))
And here is my textView:
private lazy var titleTextView: UITextView = {
let view = UITextView(frame: .zero, textContainer: nil)
view.isEditable = false
view.textContainerInset = .zero
view.textContainer.lineFragmentPadding = 0
view.textContainer.maximumNumberOfLines = 2 // Set numberOflines here!
view.textAlignment = .left
view.isScrollEnabled = false
view.delegate = self
return view
}()
But maximumNumberOfLines property don't work, it display only 1 line and followed by "..."

You need to set the lineBreakMode to a value that doesn't truncate.
Try
paragraphStyle.lineBreakMode = .byWordWrapping

When i set the linespacing property, the size computered by UITextView.sizeToFit() is not height enough to display more than 1 line.
But in UILabel, call sizeToFit will computer a appropriate height for you to display as more lines as you want.

Try:
view.textContainer.maximumNumberOfLines = 2
view.textContainer.lineBreakMode = .byTruncatingTail

removing linebreakmode of paragraphStyle used by attributed text works for me.

Related

UILabel text alignment not working (Swift 4)

I'm trying to align the text in a UILabel but it's not working. The text prints with the second line of the label hugging the left side of the label. How do I make both lines aligned in the center of the label? Thanks.
let bioTextView: UILabel = {
let tv = UILabel()
tv.text = "This is sample text for a bio label for a user on this platform."
tv.backgroundColor = .clear
tv.textColor = .white
tv.lineBreakMode = .byWordWrapping
tv.numberOfLines = 0
tv.textAlignment = NSTextAlignment.right
return tv
}()
Please find the below screenshot for the issue. My requirement is to fit the text in tow lines.
Try setting the alignment after you have added the view as a subview.
view.addSubview(self.bioTextView)
bioTextView.textAlignment = .center
Try this one:
let bioTextView: UILabel = {
let tv = UILabel()
tv.backgroundColor = .clear
tv.textColor = .white
tv.lineBreakMode = .byWordWrapping
tv.numberOfLines = 0
let textString = NSMutableAttributedString(
string: "This is sample text for a bio label for a user on this platform.",
attributes: [:])
let textRange = NSRange(location: 0, length: textString.length)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
textString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: textRange)
tv.attributedText = textString
return tv
}()
If someone is using UIStackView and has encountered this problem: stackView.alignment can ruin label.textAlignment property. Simply remove stackView.alignment.
Update following line fo code will fix your issue:
tv.textAlignment = .center
This will align your label text to center.

Swift 3 UILabel, how to word wrap after changing text

I have a UILabel which has been created programmatically and want to set the text property dynamically after its creation. I can word wrap it during init but not subsequently. After the title label text is changed it keeps one line, regardless of whether I set the number of lines to 2 or 0 and word wrap or not. After I change the title I want it to occupy 2 lines and the text is easily long enough for this to happen but it does not.
let titleLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = .clear
label.layer.masksToBounds = true
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.textColor = .white
return label
}()
var titleLabelText: String? {
didSet {
titleLabel.text = titleLabelText
titleLabel.layoutIfNeeded()
}
}
then later...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
titleLabelText = "some string which needs word wrapping"
}
titleLabel.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
titleLabel.widthAnchor.constraint(equalToConstant: screenWidth - 90).isActive = true
Font size is UIFont(name: "Muli", size: 12)
Here is how I load my label in viewDidLoad() but the label.text is applied in viewDidAppear()
let headerStackView: UIStackView = {
let headerArray = [welcomeLabel]
let stackView = UIStackView(arrangedSubviews: headerArray)
When you set your label to display multiple line..Remember your label must have enough height that can hold your text to be display multiple line.
Try to increase height of your label, Check width is proper and then check with your code.
If your text gets increases decrease the font size, it will automatically show complete text in your label.
and set the label line space to 0 and allow word wrap property true
select your label and try this one
AFAIK You need to add it as attributedText, then create an NSAttributedString, with your string and attributes.
let paragraphStyleWithWordWrapping = NSMutableParagraphStyle()
paragraphStyleWithWordWrapping.lineBreakMode = .byWordWrapping
let attributedString = NSAttributedString(myString, [NSParagraphStyleAttributeName: paragraphStyleWithWordWrapping])
label.attributedText = attributedString

UILabel text truncation vs. line breaks in text

I have a UILabel that is put as titleView in the navigation bar. I want it to have 2 lines, where the first line can be truncated and the second is center aligned.
In code it looks more less like this:
let label = UILabel()
let text = NSAttributedString(string: "Long long long text\nsecond line")
label.attributedText = text
label.textAlignment = .Center
label.numberOfLines = 0
label.lineBreakMode = .ByTruncatingTail
label.sizeToFit()
self.navigationItem.titleView = label
The effect in case of the first line text is not exceeding available
space is like this:
It's pretty good, but when the first line text is longer than:
let text = NSAttributedString(string: "Very very very very very long text\nsecond line")
I want to achieve like below.
How it can be done? I experimented with numberOfLines and lineBreakMode but it's not worked.
change your line breakmode to ByTruncatingMiddle instead of ByTruncatingTail. Something like below,
label.lineBreakMode = .ByTruncatingMiddle
Hope this will help :)
Navigation Tittle with sub-Tittle (Multiline Navigation Tittle)
Use NSMutableAttributedString with UITextView instead of UILabel
(because, if tittle is large then UILabel lineBreakMode with .byTruncatingTail is not working for first line in UILabel)
func multilineNavigation(title:String,subTitle:String) {
DispatchQueue.main.async {
let titleAttributedStr = NSMutableAttributedString(string: title, attributes: [NSAttributedStringKey.foregroundColor: UIColor.orange,NSAttributedStringKey.font: UIFont(name: "Helvetica Neue", size: 17.0) ?? UIFont()])
let subTitleAttributedStr = NSMutableAttributedString(string: "\n\(subTitle)", attributes: [NSAttributedStringKey.foregroundColor: UIColor.green,NSAttributedStringKey.font: UIFont(name: "Helvetica Neue", size: 12.0) ?? UIFont()])
titleAttributedStr.append(subTitleAttributedStr)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 1
paragraphStyle.lineBreakMode = .byTruncatingTail
titleAttributedStr.addAttribute(.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, titleAttributedStr.length))
let textView = UITextView()
textView.attributedText = titleAttributedStr
textView.backgroundColor = .clear
textView.isUserInteractionEnabled = false
textView.textContainerInset = .zero
textView.textAlignment = .center
textView.frame = CGRect(x: 0, y: 0, width: textView.intrinsicContentSize.width, height: 44)
self.navigationItem.titleView = textView
}
}

How to adjust a UILabel line spacing programmatically in Swift?

I have a multiline UILabel as shown here:
I achieved this using the following code:
label.lineBreakMode = .ByWordWrapping
label.numberOfLines = 2
I'm trying to "decrease" the line spacing between the 1st line and 2nd line, and I tried to use the following code:
let text = label.attributedText
let mas = NSMutableAttributedString(attributedString:text!)
mas.replaceCharactersInRange(NSMakeRange(0, mas.string.utf16.count),
withString: label.text!)
label.attributedText = mas
However, it does not seem to work.
Thanks
Programmatically with 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\nadjust\na\nUILabel\nline\nspacing\nprogrammatically\nin\nSwift"
// 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\nadjust\na\nUILabel\nline\nspacing\nprogrammatically\nin\nSwift"
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
Swift 3
let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
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
attrString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
label.attributedText = attrString
From Interface Builder:
You're on the right track with NSAttributedString. You need to set the line spacing of the paragraph style:
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 30 // Whatever line spacing you want in points
attributedString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
label.attributedText = attributedString;
Do this in the storyboard.....
func updateLabel(with title: String) {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineHeightMultiple = 0.8
paragraphStyle.alignment = .center
let string = NSAttributedString(string: title, attributes: [.paragraphStyle: paragraphStyle])
label.attributedText = string
}

centering text in a UILabel with an NSAttributedString

Going through some basic improvements to a application I am working on. Still new to the iOS swift development scene. I figured that the lines of text in my code would automatically be centered because I set the label to center. After a little bit of research I discovered this is not the case. How would I align code like this to center:
let atrString = try NSAttributedString(
data: assetDetails!.cardDescription.dataUsingEncoding(NSUTF8StringEncoding)!,
options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType],
documentAttributes: nil)
assetDescription.attributedText = atrString
You need to create a paragraph style specifying center alignment, and set that paragraph style as an attribute on your text. Example playground:
import UIKit
import PlaygroundSupport
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.center
let richText = NSMutableAttributedString(string: "Going through some basic improvements to a application I am working on. Still new to the iOS swift development scene. I figured that the lines of text in my code would automatically be centered because I set the label to center.",
attributes: [ NSParagraphStyleAttributeName: style ])
// In Swift 4, use `.paragraphStyle` instead of `NSParagraphStyleAttributeName`.
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 400))
label.backgroundColor = UIColor.white
label.attributedText = richText
label.numberOfLines = 0
PlaygroundPage.current.liveView = label
Result:
Since you're parsing an HTML document to create your attributed string, you'll need to add the attribute after creation, like this:
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.center
let richText = try NSMutableAttributedString(
data: assetDetails!.cardDescription.data(using: String.Encoding.utf8)!,
options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType],
documentAttributes: nil)
richText.addAttributes([ NSParagraphStyleAttributeName: style ],
range: NSMakeRange(0, richText.length))
// In Swift 4, use `.paragraphStyle` instead of `NSParagraphStyleAttributeName`.
assetDescription.attributedText = richText
Update for Swift 4
In Swift 4, attribute names are now of type NSAttributeStringKey and the standard attribute names are static members of that type. So you can add the attribute like this:
richText.addAttribute(.paragraphStyle, value: style, range: NSMakeRange(0, richText.length))
In Swift 4.1 :
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.center
lbl.centerAttributedText = NSAttributedString(string: "Total Balance",attributes: [.paragraphStyle: style])
(edited for code block)
You can use this utility function to do all common configuration for label
#discardableResult
public func DULabel(text: String, frame: CGRect = .zero, parent:UIView? = nil , font:UIFont, textColor:UIColor = .black, numOfLines:Int = 0 ,textAlignment: NSTextAlignment = .center,lineSpaceing:CGFloat = 0, cb: ((UILabel)->Void)? = nil )-> UILabel! {
let label = UILabel()
label.frame = frame
label.font = font
label.textColor = textColor
label.textAlignment = textAlignment
label.numberOfLines = numOfLines
if( lineSpaceing == 0 ){
label.text = text
}
else {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpaceing
paragraphStyle.alignment = textAlignment
let attrString = NSMutableAttributedString(string: text)
attrString.addAttribute(.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
label.attributedText = attrString
}
if let parent = parent {
parent.addSubview(label)
}
cb?(label)
return label
}

Resources