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
I'm trying to dynamically set my navigation bar's text so that the header text always fits. I'm acccomplishing that like this:
// Pet's Day text "Joy's Day"
if let range = currentPet.range(of: "_") {
let petsName = currentPet[range.upperBound..<currentPet.endIndex]
let deviceWidth = UIScreen.main.bounds.size.width
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: deviceWidth, height: 40))
titleLabel.text = "\(petsName)'s Day"
titleLabel.font = UIFont.systemFont(ofSize: 30)
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.white
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.5
titleLabel.textAlignment = .center
self.navBar.topItem?.titleView = titleLabel
}
However, as seen by this picture, this lowers the header text below its natural height:
The navigation bar on the left is from one of my app's other views, while the one on the right is the one I'm setting.
Both of these navigation bars are navigation bars that I've dragged in and made the prompt equal to an empty string to increase their height:
Can anybody please help me implement my code above so that it doesn't drop down the header text?
**Edit: Here are screenshots from Xcode's debug hierarchy:
This is the normal navigation bar:
This is the one I'm setting:
You need to set the baseline, by default is Align Baseline, you need to change to Align Centers
Code example:
class TestViewController: UIViewController {
#IBOutlet weak var navBar: UINavigationBar!
override func viewDidLoad() {
super.viewDidLoad()
// Change the height of the navbar
self.navBar.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 68)
let deviceWidth = UIScreen.main.bounds.size.width
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: deviceWidth, height: 40))
titleLabel.text = "Log Events" // Change to Joy's Day and check the result
titleLabel.font = UIFont.systemFont(ofSize: 30)
titleLabel.baselineAdjustment = .alignBaselines
titleLabel.textColor = UIColor.white
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.5
titleLabel.textAlignment = .center
self.navBar.topItem?.titleView = titleLabel
}
}
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")
I have some labels which I want to adjust their height to the text, this is the code I wrote for this now
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
EDIT:
The issue was not in this piece of code, so my fix is in the question itself. It might still be useful for others!
I've just put this in a playground and it works for me.
Updated for Swift 4.0
import UIKit
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
let font = UIFont(name: "Helvetica", size: 20.0)
var height = heightForView("This is just a load of text", font: font, width: 100.0)
Swift 3:
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
If you are using AutoLayout, you can adjust UILabel height by config UI only.
For iOS8 or above
Set constraint leading/trailing for your UILabel
And change the lines of UILabel from 1 to 0
For iOS7
First, you need to add contains height for UILabel
Then, modify the Relation from Equal to Greater than or Equal
Finally, change the lines of UILabel from 1 to 0
Your UILabel will automatically increase height depending on the text
In swift 4.1 and Xcode 9.4.1
Only 3 steps
Step 1)
//To calculate height for label based on text size and width
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat {
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
Step 2)
//Call this function
let height = heightForView(text: "This is your text", font: UIFont.systemFont(ofSize: 17), width: 300)
print(height)//Output : 41.0
Step 3)
//This is your label
let proNameLbl = UILabel(frame: CGRect(x: 0, y: 20, width: 300, height: height))
proNameLbl.text = "This is your text"
proNameLbl.font = UIFont.systemFont(ofSize: 17)
proNameLbl.numberOfLines = 0
proNameLbl.lineBreakMode = .byWordWrapping
infoView.addSubview(proNameLbl)
I have the strong working solution.
in layoutSubviews:
title.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 0)
title.sizeToFit()
title.frame.size = title.bounds.size
in text setter:
title.text = newValue
setNeedsLayout()
UPD.
of course with this UILabel settings:
title.lineBreakMode = .byWordWrapping
title.numberOfLines = 0
I create this extension if you want
extension UILabel {
func setSizeFont (sizeFont: CGFloat) {
self.font = UIFont(name: self.font.fontName, size: sizeFont)!
self.sizeToFit()
}
}
based on Anorak's answer, I also agree with Zorayr's concern, so I added a couple of lines to remove the UILabel and return only the CGFloat, I don't know if it helps since the original code doesn't add the UIabel, but it doesn't throw error, so I'm using the code below:
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
var currHeight:CGFloat!
let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.font = font
label.text = text
label.sizeToFit()
currHeight = label.frame.height
label.removeFromSuperview()
return currHeight
}
Just by setting:
label.numberOfLines = 0
The label automatically adjusts its height based upon the amount of text entered.
The solution suggested by Anorak as a computed property in an extension for UILabel:
extension UILabel
{
var optimalHeight : CGFloat
{
get
{
let label = UILabel(frame: CGRectMake(0, 0, self.frame.width, CGFloat.max))
label.numberOfLines = 0
label.lineBreakMode = self.lineBreakMode
label.font = self.font
label.text = self.text
label.sizeToFit()
return label.frame.height
}
}
}
Usage:
self.brandModelLabel.frame.size.height = self.brandModelLabel.optimalHeight
Following on #Anorak answer, i added this extension to String and sent an inset as a parameter, because a lot of times you will need a padding to your text.
Anyway, maybe some you will find this usefull.
extension String {
func heightForWithFont(font: UIFont, width: CGFloat, insets: UIEdgeInsets) -> CGFloat {
let label:UILabel = UILabel(frame: CGRectMake(0, 0, width + insets.left + insets.right, CGFloat.max))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.font = font
label.text = self
label.sizeToFit()
return label.frame.height + insets.top + insets.bottom
}
}
Here is how to calculate the text height in Swift. You can then get the height from the rect and set the constraint height of the label or textView, etc.
let font = UIFont(name: "HelveticaNeue", size: 25)!
let text = "This is some really long text just to test how it works for calculating heights in swift of string sizes. What if I add a couple lines of text?"
let textString = text as NSString
let textAttributes = [NSFontAttributeName: font]
let textRect = textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil)
just call this method where you need dynamic Height for label
func getHeightforController(view: AnyObject) -> CGFloat {
let tempView: UILabel = view as! UILabel
var context: NSStringDrawingContext = NSStringDrawingContext()
context.minimumScaleFactor = 0.8
var width: CGFloat = tempView.frame.size.width
width = ((UIScreen.mainScreen().bounds.width)/320)*width
let size: CGSize = tempView.text!.boundingRectWithSize(CGSizeMake(width, 2000), options:NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: tempView.font], context: context).size as CGSize
return size.height
}
Swift 4.0
self.messageLabel = UILabel(frame: CGRect(x: 70, y: 60, width:UIScreen.main.bounds.width - 80, height: 30)
messageLabel.text = message
messageLabel.lineBreakMode = .byWordWrapping //in versions below swift 3 (messageLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping)
messageLabel.numberOfLines = 0 //To write any number of lines within a label scope
messageLabel.textAlignment = .center
messageLabel.textColor = UIColor.white
messageLabel.font = messageLabel.font.withSize(12)
messageLabel.sizeToFit()
Blockquote NSParagraphStyle.LineBreakMode, apply to entire paragraphs, not words within paragraphs.This property is in effect both during normal drawing and in cases where the font size must be reduced to fit the label’s text in its bounding box. This property is set to byTruncatingTail by default.
This link describes the storyboard way of doing the same
Swift 4.0
Instead of calculating the text/label height, I just resize the label after inserting the (dynamic) text.
Assuming that myLabel is the UILabel in question:
let myLabel = UILabel(frame: CGRect(x: 0, y: 0, width: *somewidth*, height: *placeholder, e.g. 20*))
myLabel.numberOfLines = 0
myLabel.lineBreakMode = .byWordWrapping
...
And now comes the fun part:
var myLabelText: String = "" {
didSet {
myLabel.text = myLabelText
myLabel.sizeToFit()
}
}
The Swift 4.1 extension method to calculate label height:
extension UILabel {
func heightForLabel(text:String, font:UIFont, width:CGFloat) -> CGFloat {
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
}
Swift 5, XCode 11 storyboard way. I think this works for iOS 9 and higher. You want for example "Description" label to get the dynamic height, follow the steps:
1) Select description label -> Go to Attributes Inspector (pencil icon), set:
Lines: 0
Line Break: Word Wrap
2) Select your UILabel from storyboard and go to Size Inspector (ruler icon),
3) Go down to "Content Compression Resistance Priority to 1 for all other UIView (lables, buttons, imageview, etc) components that are interacting with your label.
For example, I have UIImageView, Title Label, and Description Label vertically in my view. I set Content Compression Resistance Priority to UIImageView and title label to 1 and for description label to 750. This will make a description label to take as much as needed height.
You can also use sizeThatFits function.
For example:
label.sizeThatFits(superView.frame.size).height
To make label dynamic in swift , don't give height constarint and in storyboard make label number of lines 0 also give bottom constraint and this is the best way i am handling dynamic label as per their content size .