NSAttributedString with tabs - ios

How do you create a UILabel with this kind of text format? Would you use NSAttributedString?

NSAttributedString can create text columns with tab stops. This is similar to how it is done in a word processor with the same limitations.
let text = "Name\t: Johny\nGender\t: Male\nAge\t: 25\nFavourites\t: Reading, writing"
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.tabStops = [NSTextTab(textAlignment: NSTextAlignment.Left, location: 150, options: [:])]
paragraphStyle.headIndent = 150
label.attributedText = NSAttributedString(string: text, attributes: [NSParagraphStyleAttributeName: paragraphStyle])
tabStops provides point positions for where to continue text after each tab. Here we did one tab at a reasonable point after the first column.
headIndent tells the label that wrapped text needs to be indented by a fixed amount, so it wraps to the next line.
The limitations with this approach are:
The tab stop location is a fixed point value so you need to know what you want. If the value you pick is less than the width of the first column for some lines, those lines will indent to a different location.
Wrapping only really works if your last column is the one that wraps. Since your second column was prefaced by ":" You may want to either just increase your headIndent or also split out the ":" to be \t:\t and set up a second tab stop. If you're not letting text wrap, this is not an issue.
If these limitations are too restrictive, you can restructure your label to be a collection of multiple labels with auto layout constraints.

In Swift 4.2 or above
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.tabStops = [NSTextTab.init(textAlignment: .left, location: 150, options: [:])]
paragraphStyle.headIndent = 150
let attributedTitle = NSAttributedString(string: "Some Title", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14.0), NSAttributedString.Key.paragraphStyle: paragraphStyle])

Related

How to apply Atrributed String different spacing between lines in swift

I want to apply spacing between first two lines in attributed string and third line should look like paragraph.
Expected output :
Expected output screenshot
Current Implemenation:
Current implementaion screenshot
Here is the code tried by me.
let myString = "Your account phone numbers are listed here.\nTo change or delete a phone number, tap on it.\nTo add a phone number, go to the top right-hand corner of your screen and tap on “Add”.";
let font = UIFont.systemFont(ofSize: 14)
let attributedString = NSMutableAttributedString(string: myString, attributes: [.font: font])
self.displayLabel.attributedText = attributedString
I created label and setting number of lines 0 so it will display multiline text.
In the label need to show space in the first two lines as shown in expected output screenshot.
How to apply spacing only to first two lines and third line should display as shown in expected output screenshot?
You seem to want to set the spacing between paragraphs. This is controlled by NSParagraphStyle.paragraphSpacing. Just set the .paragraphStyle attribute of the attributed string to an NSParagraphStyle:
let paraStyle = NSMutableParagraphStyle()
paraStyle.paragraphSpacing = 10 // or some other number
let attributedString = NSMutableAttributedString(string: myString,
attributes: [
.font: font,
.paragraphStyle: paraStyle
])

NSAttributedString text always sticks to bottom with big lineHeight

I'm trying to implement by-design labels coming from Sketch e.g. I need text styles with font size = 19 and line height = 50. So I ended up using NSAttributedString with NSMutableParagraphStyle but was stopped by problem with text being sticked to bottom of UILabel
I've already tried to use lineHeightMultiple and lineSpacing but those didn't give me the line height I wanted so I ended up using minimumLineHeight and maximumLineHeight equal the same
Here is my approach to make NSAttributedString
private static func makeAttributedString(
with attributes: TextAttributes,
text: String? = nil,
alignment: NSTextAlignment = .center
) -> NSAttributedString {
let font = UIFont(name: attributes.font.rawValue, size: attributes.fontSize)!
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = alignment
paragraph.paragraphSpacing = attributes.paragraph
paragraph.minimumLineHeight = attributes.lineHeight // equal 50 in my case
paragraph.maximumLineHeight = attributes.lineHeight // equal 50 in my case
let attributes: [NSAttributedStringKey: Any] = [
NSAttributedStringKey.paragraphStyle: paragraph,
NSAttributedStringKey.foregroundColor: attributes.textColor,
NSAttributedStringKey.kern: attributes.kern,
NSAttributedStringKey.font: font
]
return NSAttributedString(string: text ?? "", attributes: attributes)
}
I expect result similar to design
but actually getting
Note: setting height constraint to 50 is not applicable because I also need multiline labels but there is the same bug with them
Seems like I've found some workaround myself, maybe it will help someone.
The method is about setting baselineOffset like this:
NSAttributedStringKey.baselineOffset: (attributes.lineHeight - font.lineHeight) / 4
Works like charm:
https://i.imgur.com/a2EOf5R.png

How to decrease the lineSpacing?

I have an Attributed string and I want to decrease the standard line height of it. To do so, I need to set a negative lineSpacing to my NSMutableParagraphStyle. But it's illegal according to Apple's docs.
Fun fact is that the negative lineSpacing actually works, but causes an extra bottom spacing in the UILabel which depends on the number of lines.
Is it possible to decrease the line height without having side effects?
Use NSParagraphStyle.lineHightMultiple
https://developer.apple.com/documentation/uikit/nsparagraphstyle/1528614-lineheightmultiple
You can set the lineHeightMultiple to a value greater than 0 but less than 1 and it'll reduce line spacing.
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineHeightMultiple = 0.83 //Try different values here to see what looks best
let attrString = NSMutableAttributedString(string: "Your string")
attrString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attrString.length))
You can also do this from storyboard:

UITextView attributed Alignment and size

First assume math is correct.
let textViewText = NSMutableAttributedString(string: "34\n+ 10\n+ 32344\n= 23424")
Im using a Textview to display input from the user. To make it easier to read I'm trying to get the text format like this
34
+ 10
+ 32344
= 23424
The other issue I'm having is with wrapping. Is there a way to resize each line to fit on its line?
34
= 23424
4356356
Is your text dynamic or static? If static, then all you need to do is to put the correct amount of spacing between your numbers and plus signs and then right justify the text.
self.textView.attributedText = NSMutableAttributedString(string: "34\n+ 10\n+ 32344\n= 23424")
self.textView.textAlignment = NSTextAlignment.Right
Result:
You can accomplish this by using a right-aligned tab stop in your paragraph style, and separating your operators and values with a tab.
let string = "\t34\n+\t10\n+\t32344\n=\t23424"
let paragraph = NSMutableParagraphStyle()
paragraph.tabStops = [NSTextTab(textAlignment: .Right, location: 200, options: [:])]
let attributedString = NSAttributedString(string: string, attributes:[NSParagraphStyleAttributeName: paragraph])

Can't get UILabel's text to stay on multiple lines

I have a UILabel that should display text on multiple lines in case that it's too long to stay on a single line. This how I set its parameters in interface builder:
But even by doing so, the text still gets truncated:
This is how I set the text at runtime:
let text = "left button pressed 5 seconds ago, you may want to press another button now"
let attributedText = NSMutableAttributedString(string: text)
attributedText.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(statusLabel.font.pointSize), range: (text as NSString).rangeOfString("left"))
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .ByWordWrapping
attributedText.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attributedText.length))
statusLabel.attributedText = attributedText
Like you see I even tried to add a paragraph style attribute to force the text to stay on multiple lines, but it doesn't work.
Check that you're setting the auto layout constraints so you have the top, leading and trailing spaces defined, but don't hookup a vertical height, the label will adjust itself based on the content.
Edit:

Resources