UILabel text truncation vs. line breaks in text - ios

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

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.

Navigation set titleTextAttributes failed by swift3 , Xcode 8.3

I want my navigation title using TruncationMiddle like "ABC...XYZ" .
I try to do this, but I failed.
Thanks.
self.title = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byTruncatingMiddle
self.navigationController!.navigationBar.titleTextAttributes = [NSParagraphStyleAttributeName: paragraphStyle]
I got failed in my project
Link of my project in GitHub.
UPDATE IMAGE:
You actually need to use NSMutableParagraphStyle instead of NSParagraphStyle.
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byTruncatingMiddle
self.navigationController?.navigationBar.titleTextAttributes = [NSParagraphStyleAttributeName: paragraphStyle]
The lineBreakMode attribute then has a setter that you can use instead of setting the value directly with the key which is not allowed with the NSParagraphStyle class and the truncationMode key.
Try to add Custom Label in Navigation bar.
let label = UILabel(frame: CGRect(x:0, y:0, width:400, height:50))
label.backgroundColor = UIColor.clear
label.numberOfLines = 1
label.font = UIFont.boldSystemFont(ofSize: 13.0)
label.textAlignment = .center
label.textColor = UIColor.black
label.lineBreakMode = .truncateMiddle
self.navigationItem.titleView = label
// OR
// self.navigationController!.navigationBar.topItem.titleView = label
You can also show multiline in label if you want then just set numberOfLines to 0 and linebreak mode to worldwrap :)
Hope it is helpful
You just need to add following line into your code:
self.title = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
let navLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
navLabel.text = self.title
navLabel.textColor = .white
navLabel.font = UIFont(name: "Helvetica-Bold", size: 14.0)
navLabel.backgroundColor = .clear
navLabel.adjustsFontSizeToFitWidth = false
navLabel.lineBreakMode = .byTruncatingMiddle
self.navigationItem.titleView = navLabel

Xcode 8.3.3 - How can I make 2 rows in a label?

So basically, I have created a speedometer but right now I have it outputting "30km/h" on one line.
What I want it to look like is have 30 on one line and km/h below it.
And if anyone knows how to make that thicker line that goes up the faster you go, that would be a great help.
Here is what my code looks like right now:
let speed = (location.speed*3.6)
let speedInt: Int = Int(speed)
//statusLabel.backgroundColor = UIColor.red
//statusLabel.layer.cornerRadius = 10.0
//statusLabel.clipsToBounds = true
let statusLabel = UILabel()
let size:CGFloat = 70.0
statusLabel.textColor = UIColor.black
statusLabel.textAlignment = .center
statusLabel.font = UIFont.systemFont(ofSize: 13.0)
statusLabel.frame = CGRect(x : 172.0,y : 580.0,width : size, height : size)
statusLabel.layer.cornerRadius = size / 2
statusLabel.layer.borderWidth = 2.0
statusLabel.layer.backgroundColor = UIColor.white.cgColor
statusLabel.layer.borderColor = UIColor.init(colorLiteralRed: 14.0/255, green: 122.0/255, blue: 254.0/255, alpha: 1.0).cgColor
statusLabel.text = "\(speedInt) km/h"
You should use UILabel's attributedText property in order to achieve this look.
Use \n to insert a new line to the label.
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let bigAttr = [NSForegroundColorAttributeName: UIColor.white,
NSFontAttributeName: UIFont.systemFont(ofSize: 60, weight: UIFontWeightLight),
NSParagraphStyleAttributeName: paragraphStyle]
let smallAttr = [NSFontAttributeName: UIFont.systemFont(ofSize: 12, weight: UIFontWeightLight)]
let attributedString = NSMutableAttributedString(string: "\(speedInt)", attributes: bigAttr)
attributedString.append(NSAttributedString(string: "\nkm/h", attributes: smallAttr))
statusLabel.attributedText = attributedString
Add a \n where you want to split the string. "30 \n kmh"
Or simply add two labels.
You can simply add 2 lines in label with the help of UI. Just take a look at below snap
as shown above you can set the line break by word wrapping and simply add the title whole you want. in your case 0 km/h.
Then put the cursor at k and press ctrl + Enter. The title will appears in two lines.

Underline covers text in NSAttributedString

I'm trying to create an attributed string but the underline covers my text instead of appearing behind it:
Is there a way to fix this? I'm using the following code:
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 10.0
let attributes = [NSForegroundColorAttributeName: UIColor.white,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleThick.rawValue,
NSUnderlineColorAttributeName: UIColor.red,
NSParagraphStyleAttributeName: paragraphStyle]
let attributedString = NSAttributedString(string: "Story", attributes: attributes)
Thanks!
EDIT:
To give more context:
I'm displaying the attributed string on a UILabel placed in a .xib file:
view.textLabel.attributedText = attributedString
The label has the following font:
System Bold 32.0
I'm running the code on iPhone 6 - iOS 10.3 simulator.
EDIT 2:
I should have mentioned that the label may, at some point, contain more than one line of text. That's why the numberOfLines is set to 0.
EDIT 3:
If anybody encounters this problem -- it seems that there is a lot of difference in how underline is drawn on iOS 9 vs 10 as well as UILabel vs UITextView. I've ended up having to draw the underline myself by subclassing NSLayoutManager.
Yes, there is such problem as you have described. It shows up when you use multiline UILabel, so not only setting numberOfLines to 0, but type more than 1 line in it.
Example
let selectedStringAttributes: [String: Any]
= [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 28),
NSForegroundColorAttributeName: UIColor.green,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue,
NSUnderlineColorAttributeName: UIColor.green]
let label = UILabel(frame: CGRect(x: 100, y: 100, width: 500, height: 100))
label.numberOfLines = 0
label.attributedText = NSAttributedString(string: "String to test underline", attributes: selectedStringAttributes)
And everything will look pretty good.
But if you want to use such text:
label.attributedText = NSAttributedString(string: "String to\ntest underline", attributes: selectedStringAttributes)
or label's width is too short, than:
So the reason for such behaviour is of course bug in NSAttributedString. As it mentioned in radar there is a workaround
You should add this attribute to your NSAttributedString
NSBaselineOffsetAttributeName: 0
And magic will happen.
Instead of using NSAttributedString you can draw border below the label with x space using this.
let space:CGFloat = 10
let border = CALayer()
border.backgroundColor = UIColor.red.cgColor
border.frame = CGRect(x: 0, y: (label?.frame.size.height)! + space, width: (label?.frame.size.width)!, height: 1)
label?.layer.addSublayer(border)
On my machine, showing your attributed string in a black-backgrounded UILabel, it makes a quite nice-looking display:
The red thick underline is nicely separated from the text, and is interrupted to allow the descender of the "y" to pass through it.
NOTE You cannot combine the font of the UILabel (set in Interface Builder) with its attributedText. You must set the entire label's text formatting in the attributedText. So, my code looks like this:
let attributes : [String:Any] = [NSForegroundColorAttributeName: UIColor.white,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleThick.rawValue,
NSUnderlineColorAttributeName: UIColor.red,
NSFontAttributeName: UIFont.boldSystemFont(ofSize: 32)]
let attributedString = NSAttributedString(string: "Story", attributes: attributes)
lab.backgroundColor = .black
lab.attributedText = attributedString
(You will notice that I removed your stipulation of the paragraph line spacing; there is only one line, so this stipulation adds nothing. However, I get the same result even if I restore it.)
So this is my solution to this issue.
I think it is "cleaner" and easier.
Post me if you dont understand :)
class BottomLineTextField: UITextField {
var bottomBorder = UIView()
override func awakeFromNib() {
super.awakeFromNib()
setBottomBorder()
}
func setBottomBorder() {
self.translatesAutoresizingMaskIntoConstraints = false
bottomBorder = UIView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
hasError = false
bottomBorder.translatesAutoresizingMaskIntoConstraints = false
addSubview(bottomBorder)
bottomBorder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
bottomBorder.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
bottomBorder.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
bottomBorder.heightAnchor.constraint(equalToConstant: 1).isActive = true // Set underline height
}
}

Multiline Navigationbar Title

I am trying to set the title label in my navigation bar to allow multiple lines. I have custom navigation controller code that I am placing the multiline code into. I know that the code already there works, but my multiline part is not working.
let titleLabel = UILabel()
titleLabel.frame = CGRectMake(0, 0, self.navigationBar.frame.width, self.navigationBar.frame.height * 2)
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .ByWordWrapping
navigationItem.titleView = titleLabel
But the text still runs off at the end. I've also tried putting this into the individual view controller itself, adding self.navigationController?. in front of navigationItem with the same results.
Is there something I'm missing in my code that would keep the title label from using multiple lines?
Here is a code example of how you can create a multiline navigationBar title
let label: UILabel = UILabel(frame: CGRectMake(0, 0, 400, 50))
label.backgroundColor = UIColor.clearColor()
label.numberOfLines = 2
label.font = UIFont.boldSystemFontOfSize(16.0)
label.textAlignment = .Center
label.textColor = UIColor.whiteColor()
label.text = "This is a\nmultiline string for the navBar"
self.navigationItem.titleView = label
Swift 5.x:
let label = UILabel()
label.backgroundColor = .clear
label.numberOfLines = 2
label.font = UIFont.boldSystemFont(ofSize: 16.0)
label.textAlignment = .center
label.textColor = .white
label.text = "This is a\nmultiline string for the navBar"
self.navigationItem.titleView = label
This is doable in a storyboard. Just drag a UIView into the Navigation bar, then drag a UILabel onto it in the document outline, set lines to 2 and alignment to center.
Use this to get the label position exactly as you want it:
let labelWidth = navBar.bounds.width - 110
let label = UILabel(frame: CGRect(x:(navBar.bounds.width/2) - (labelWidth/2), y:0, width:labelWidth, height:navBar.bounds.height))
label.backgroundColor = UIColor.clear
label.numberOfLines = 0
label.font = UIFont.boldSystemFont(ofSize: 13.0)
label.textAlignment = .center
label.textColor = UIColor.black
label.lineBreakMode = .byWordWrapping
label.text = loadedName
navBar.topItem?.title = nil
navBar.addSubview(label)
the 110 value in the top line is the spacing you want either side of the label.
swift 5+ very easy solution
func titleMultiLine(topText: String, bottomText: String) {
// let titleParameters = [NSForegroundColorAttributeName : UIColor.white,
// NSFontAttributeName : UIFont.<Font>]
// let subtitleParameters = [NSForegroundColorAttributeName : UIColor.<Color>(),
// NSFontAttributeName : UIFont.<Font>]
let titleParameters = [NSAttributedString.Key.foregroundColor : UIColor.white]
let subtitleParameters = [NSAttributedString.Key.foregroundColor : UIColor.white]
let title:NSMutableAttributedString = NSMutableAttributedString(string: topText, attributes: titleParameters)
let subtitle:NSAttributedString = NSAttributedString(string: bottomText, attributes: subtitleParameters)
title.append(NSAttributedString(string: "\n"))
title.append(subtitle)
let size = title.size()
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: size.width, height: size.height))
titleLabel.attributedText = title
titleLabel.numberOfLines = 0
titleLabel.textAlignment = .center
navigationItem.titleView = titleLabel
}
Function Calling
self.titleMultiLine(topText: "I am top text Title", bottomText: "bottom text")

Resources