Swift - UIButton with two lines of text - ios

I was wondering if it is possible to create a UIButton with two lines of text. I need each line to have a different font size. The first line will be 17 point and the second will be 11 point. I've tried messing with putting two labels inside of a UIButton, but I can't get them to stay inside the bounds of the button.
I'm attempting to do all of this in the ui builder, and not programmatically.
Thanks

There are two questions.
I was wondering if it is possible to create a UIButton with two lines
of text
This is possible through using the storyboard or programmatically.
Storyboard:
Change the 'Line Break Mode' to Character Wrap or Word Wrap and use Alt/Option + Enter key to enter a new line in the UIButton's Title field.
Programmatically:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
btnTwoLine?.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping;
}
I need each line to have a different font size
1
The worst case is, you can use a custom UIButton class and add two labels within it.
The better way is, make use of NSMutableAttributedString. Note that,this can be achieved through only programmatically.
Swift 5:
#IBOutlet weak var btnTwoLine: UIButton?
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
//applying the line break mode
textResponseButton?.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping;
let buttonText: NSString = "hello\nthere"
//getting the range to separate the button title strings
let newlineRange: NSRange = buttonText.range(of: "\n")
//getting both substrings
var substring1 = ""
var substring2 = ""
if(newlineRange.location != NSNotFound) {
substring1 = buttonText.substring(to: newlineRange.location)
substring2 = buttonText.substring(from: newlineRange.location)
}
//assigning diffrent fonts to both substrings
let font1: UIFont = UIFont(name: "Arial", size: 17.0)!
let attributes1 = [NSMutableAttributedString.Key.font: font1]
let attrString1 = NSMutableAttributedString(string: substring1, attributes: attributes1)
let font2: UIFont = UIFont(name: "Arial", size: 11.0)!
let attributes2 = [NSMutableAttributedString.Key.font: font2]
let attrString2 = NSMutableAttributedString(string: substring2, attributes: attributes2)
//appending both attributed strings
attrString1.append(attrString2)
//assigning the resultant attributed strings to the button
textResponseButton?.setAttributedTitle(attrString1, for: [])
}
Older Swift
#IBOutlet weak var btnTwoLine: UIButton?
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
//applying the line break mode
btnTwoLine?.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping;
var buttonText: NSString = "hello\nthere"
//getting the range to separate the button title strings
var newlineRange: NSRange = buttonText.rangeOfString("\n")
//getting both substrings
var substring1: NSString = ""
var substring2: NSString = ""
if(newlineRange.location != NSNotFound) {
substring1 = buttonText.substringToIndex(newlineRange.location)
substring2 = buttonText.substringFromIndex(newlineRange.location)
}
//assigning diffrent fonts to both substrings
let font:UIFont? = UIFont(name: "Arial", size: 17.0)
let attrString = NSMutableAttributedString(
string: substring1 as String,
attributes: NSDictionary(
object: font!,
forKey: NSFontAttributeName) as [NSObject : AnyObject])
let font1:UIFont? = UIFont(name: "Arial", size: 11.0)
let attrString1 = NSMutableAttributedString(
string: substring2 as String,
attributes: NSDictionary(
object: font1!,
forKey: NSFontAttributeName) as [NSObject : AnyObject])
//appending both attributed strings
attrString.appendAttributedString(attrString1)
//assigning the resultant attributed strings to the button
btnTwoLine?.setAttributedTitle(attrString, forState: UIControlState.Normal)
}
Output

I was looking for nearly the same topic, except that I don't need two different font sizes. In case someone is looking for a simple solution:
let button = UIButton()
button.titleLabel?.numberOfLines = 0
button.titleLabel?.lineBreakMode = .byWordWrapping
button.setTitle("Foo\nBar", for: .normal)
button.titleLabel?.textAlignment = .center
button.sizeToFit()
button.addTarget(self, action: #selector(rightBarButtonTapped), for: .allEvents)
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)

I have notice an issue in most of the solutions which is while making line break mode to "Character Wrap" the second line will be left aligned to the first line
To make all the lines centered.
just change the title From Plain to Attributed and then you can make each line centered

change line break to character wrap , select your button and in attribute inspector go to line break and change it to character wrap

SWIFT 3 Syntax
let str = NSMutableAttributedString(string: "First line\nSecond Line")
str.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 17), range: NSMakeRange(0, 10))
str.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 12), range: NSMakeRange(11, 11))
button.setAttributedTitle(str, for: .normal)

I have fixed this and my solution it was only in the Storyboard.
Changes:
It added in Identity Inspector -> User Defined Runtime Attributes (these KeyPaths):
numberOfLines = 2
titleLabel.textAlignment = 1
User Defined Runtime Attributes
I added this in attributes inspector:
line break = word wrap
Word wrap

You need to do some of this in code. you can't set 2 different fonts in IB. In addition to changing the line break mode to character wrap, you need something like this to set the title,
override func viewDidLoad() {
super.viewDidLoad()
var str = NSMutableAttributedString(string: "First line\nSecond Line")
str.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(17), range: NSMakeRange(0, 10))
str.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(12), range: NSMakeRange(11, 11))
button.setAttributedTitle(str, forState: .Normal)
}

New with Xcode 13 (iOS 15)
Starting with Xcode 13, the button's title and subtitle may have their attributes set separately.
Using Storyboard:
In the Attribute Inspector for the button, select "Attributed" by Title. Then change font size of the title and the subtitle.
Or Programmatically:
// Create Title
let titleSettings = AttributeContainer.font( UIFont(name: "HelveticaNeue-Italic", size: 17)! )
yourButton.configuration?.attributedTitle = AttributedString("Button's Title", attributes: titleSettings)
// Create Subtitle
let subtitleSettings = AttributeContainer.font( UIFont(name: "HelveticaNeue-Italic", size: 11)! )
yourButton.configuration?.attributedSubtitle = AttributedString("Button's Subtitle", attributes: subtitleSettings)

One way to do it is with labels, I guess. I did this, and it seems to work ok. I could create this as a UIButton and then expose the labels, I guess. I don't know if this makes any sense.
let firstLabel = UILabel()
firstLabel.backgroundColor = UIColor.lightGrayColor()
firstLabel.text = "Hi"
firstLabel.textColor = UIColor.blueColor()
firstLabel.textAlignment = NSTextAlignment.Center
firstLabel.frame = CGRectMake(0, testButton.frame.height * 0.25, testButton.frame.width, testButton.frame.height * 0.2)
testButton.addSubview(firstLabel)
let secondLabel = UILabel()
secondLabel.backgroundColor = UIColor.lightGrayColor()
secondLabel.textColor = UIColor.blueColor()
secondLabel.font = UIFont(name: "Arial", size: 12)
secondLabel.text = "There"
secondLabel.textAlignment = NSTextAlignment.Center
secondLabel.frame = CGRectMake(0, testButton.frame.height * 0.5, testButton.frame.width, testButton.frame.height * 0.2)
testButton.addSubview(secondLabel)

The suggested solutions unfortunately did not work out for me when I wanted to have a mutliline button inside a CollectionView. Then a colleague showed me a workaround which I wanted to share in case someone has the same problem - hope this helps! Create a class which inherits from UIControl and extend it with a label, which will then behave similar like a button.
class MultilineButton: UIControl {
let label: UILabel = {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.numberOfLines = 0
$0.textAlignment = .center
return $0
}(UILabel())
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(label)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
])
}
override var isHighlighted: Bool {
didSet {
backgroundColor = backgroundColor?.withAlphaComponent(isHighlighted ? 0.7 : 1.0)
label.textColor = label.textColor.withAlphaComponent(isHighlighted ? 0.7 : 1.0)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

my way:
func setButtonTitle(title: String, subtitle: String, button: UIButton){
//applying the line break mode
button.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping;
let title = NSMutableAttributedString(string: title, attributes: Attributes.biggestLabel)
let subtitle = NSMutableAttributedString(string: subtitle, attributes: Attributes.label)
let char = NSMutableAttributedString(string: "\n", attributes: Attributes.biggestLabel)
title.append(char)
title.append(subtitle)
button.setAttributedTitle(title, for: .normal)
}

Related

Enable orphan words feature for NSMutableAttributedString

The default behavior for UILabel is that it prevents orphan words to appear solely on a separate line. ie: if word wrapping happen to keep 1 word alone at the last line. iOS will prevent that by sending a word from the line before it, having two words in the last line.
The problem is that this feature doesn't work by default with NSMutableAttributedString. how can I enable it?
Sample:
var string = customField?.title ?? ""
if customField?.required == true {
string += " *"
} else {
string += " (\(getLocalizedString(localizedKey: .optional)))"
}
let style = NSMutableParagraphStyle()
if #available(iOS 14.0, *) {
style.lineBreakStrategy = .standard
}
let att = NSMutableAttributedString(string: string, attributes: [.paragraphStyle: style])
titleLabel.attributedText = att
Have in mind I am forced to use NSMutableAttributedString for other reasons. 2 labels won't work for me.
As per OP's comments...
The issue is not with Attributed Text, as the same thing happens with "normal" text.
With iOS 11 (may have been 10), Apple changed UIKit to prevent orphans when a UILabel wraps to two lines of text. Orphans are still allowed with more than two lines:
A was prior to iOS 11... B is current... C is current with more than two lines...
Note the D example -- I don't have the Xcode beta installed, but based on other comments I've seen it appears that in iOS 16 the "no orphan" rule will also be applied when the text wraps to more than two lines.
So... a way to solve your issue is to use a "non-break-space" character between the last word and the asterisk (instead of a plain space).
Here's a quick test:
class WrapTestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 4
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
stackView.widthAnchor.constraint(equalToConstant: 320.0),
])
var noteLabel: UILabel!
var testLabel: UILabel!
let noteFont: UIFont = .systemFont(ofSize: 14.0)
noteLabel = UILabel()
noteLabel.font = noteFont
noteLabel.numberOfLines = 0
noteLabel.text = "Just enough to fit:"
stackView.addArrangedSubview(noteLabel)
testLabel = UILabel()
testLabel.backgroundColor = .yellow
testLabel.numberOfLines = 0
testLabel.attributedText = sampleAttrString(method: 0)
stackView.addArrangedSubview(testLabel)
stackView.setCustomSpacing(20.0, after: testLabel)
noteLabel = UILabel()
noteLabel.font = noteFont
noteLabel.numberOfLines = 0
noteLabel.text = "Using a space char:"
stackView.addArrangedSubview(noteLabel)
testLabel = UILabel()
testLabel.backgroundColor = .yellow
testLabel.numberOfLines = 0
testLabel.attributedText = sampleAttrString(method: 1)
stackView.addArrangedSubview(testLabel)
stackView.setCustomSpacing(20.0, after: testLabel)
noteLabel = UILabel()
noteLabel.font = noteFont
noteLabel.numberOfLines = 0
noteLabel.text = "Using a non-break-space char:"
stackView.addArrangedSubview(noteLabel)
testLabel = UILabel()
testLabel.backgroundColor = .yellow
testLabel.numberOfLines = 0
testLabel.attributedText = sampleAttrString(method: 2)
stackView.addArrangedSubview(testLabel)
stackView.setCustomSpacing(20.0, after: testLabel)
noteLabel = UILabel()
noteLabel.font = noteFont
noteLabel.numberOfLines = 0
noteLabel.text = "Although, iOS 16 may give:"
stackView.addArrangedSubview(noteLabel)
testLabel = UILabel()
testLabel.backgroundColor = .yellow
testLabel.numberOfLines = 0
testLabel.attributedText = sampleAttrString(method: 3)
stackView.addArrangedSubview(testLabel)
stackView.setCustomSpacing(20.0, after: testLabel)
}
func sampleAttrString(method: Int) -> NSMutableAttributedString {
let fontA: UIFont = .systemFont(ofSize: 20.0, weight: .bold)
let attsA: [NSAttributedString.Key : Any] = [
.font: fontA,
.foregroundColor: UIColor.blue,
]
let attsB: [NSAttributedString.Key : Any] = [
.font: fontA,
.foregroundColor: UIColor.red,
]
var partOne = NSMutableAttributedString(string: "If the label has enough text so it wraps to more than two lines, UIKit will allow a last word orphan.", attributes: attsA)
var partTwo: NSAttributedString = NSAttributedString()
switch method {
case 0:
()
case 1:
partTwo = NSAttributedString(string: " *", attributes: attsB)
case 2:
partTwo = NSAttributedString(string: "\u{a0}*", attributes: attsB)
case 3:
partOne = NSMutableAttributedString(string: "If the label has enough text so it wraps to more than two lines, UIKit will allow a last\nword orphan.", attributes: attsA)
partTwo = NSAttributedString(string: "\u{a0}*", attributes: attsB)
default:
()
}
partOne.append(partTwo)
return partOne
}
}
Output:
So... you'll want to test that with iOS 16, and, if that's the case, you may need to do a version check to determine wether to add a plain space or a non-break-space.
It is a change by Apple since iOS11 (as answered by #DonMag) to prevent orphaned word in the last line.
If your production only support iOS13.0+, setting the lineBreakStrategy will set it back to the old style.
let label = UILabel()
if #available(iOS 14.0, *) {
label.lineBreakStrategy = NSParagraphStyle.LineBreakStrategy()
}
(One interesting thing is, I found this lineBreakStrategy also work on iOS 13.0+, even tho from Apple's document it mentioned iOS 14.0+.)
If you need to support older iOS version, you need to set the value of the NSAllowsDefaultLineBreakStrategy key when application launch, which I cannot find any document about it. I tested it worked on iOS 11 & 12, but not on iOS 13.0+.
// Setting the undocumented key NSAllowsDefaultLineBreakStrategy
UserDefaults.standard.set(false, forKey: "NSAllowsDefaultLineBreakStrategy")
So you might need both if your app support iOS 11.0+. Hope it helps ;)
From the documentation of the lineBreakStrategy property on UILabel, which helps control this behavior:
When the label has an attributed string value, the system ignores the textColor, font, textAlignment, lineBreakMode, and lineBreakStrategy properties. Set the NSForegroundColorAttributeName, NSFontAttributeName, alignment, lineBreakMode, and lineBreakStrategy properties in the attributed string instead.
If you want to use a specific line break strategy, like .standard ("The text system uses the same configuration of line-break strategies that it uses for standard UI labels. "), you will need to apply the attribute to the attributed string via a paragraph style:
let style = NSMutableParagraphStyle()
style.lineBreakStrategy = .standard
let text = NSMutableAttributedString(
string: "long title with an asterisk at the end *",
attributes: [.paragraphStyle: style]
)
titleLabel.attributedText = text
Depending on your text, it may also help to set allowsDefaultTighteningForTruncation on the paragraph style because that may allow the text system to tighten the space between words on the last line of the string to get everything to fit. (I say may because this property controls truncation specifically, but it's possible that the text system can take it into account for wrapping as well.)

How to change UIButton attributed text colour programatically?

I have a subclass (KeyButton) of UIButton where I am applying certain styles for the button. The following code adds the attributed text for buttons in the ViewController.
func superScriptText(text: String, button: KeyButton, fontSize: Int) {
let font:UIFont? = UIFont.systemFont(ofSize: 22, weight: UIFont.Weight.light)
let fontSuper:UIFont? = UIFont(name: "Helvetica", size:CGFloat(fontSize))
let attString:NSMutableAttributedString = NSMutableAttributedString(string: text, attributes: [.font:font!])
attString.setAttributes([.font:fontSuper!,.baselineOffset:15], range: NSRange(location:1,length:1))
button.setAttributedTitle(attString, for: .normal)
}
How can I change the color of attributed text for the button in the class?
Just change:
let attString:NSMutableAttributedString =
NSMutableAttributedString(string: text, attributes: [.font:font!])
to:
let attString:NSMutableAttributedString =
NSMutableAttributedString(string: text, attributes: [.font:font!, .foregroundColor: UIColor.red])
NSAttributedStringKey.foregroundColor is used for the text color, see more options in docs.
You have to add the .foregroundColor key with a UIColor object as the value to the NSAttributedStrings attributes dictionary.
Example (assuming you have added a custom button in storyboard):
class CustomButton: UIButton {
override func awakeFromNib() {
super.awakeFromNib()
let text = "CustomButton"
let font = UIFont.systemFont(ofSize: UIFont.buttonFontSize)
let textColor = UIColor.orange
let attributes: [NSAttributedStringKey: Any] = [
.font: font,
.foregroundColor: textColor
]
let attributedText = NSAttributedString(string: text, attributes: attributes)
self.setAttributedTitle(attributedText, for: .normal)
}
}
I couldn't do this through UIButton subclass. I created the subclass of NSAttributtedText and add the following method:
var textColor: UIColor?
func setSuperScript(text: String, button: KeyButton, fontSize: Int) {
let font:UIFont? = UIFont.systemFont(ofSize: 22, weight: UIFont.Weight.light)
let fontSuper:UIFont? = UIFont(name: "Helvetica", size:CGFloat(fontSize))
let attString:NSMutableAttributedString = NSMutableAttributedString(string: text, attributes: [.font:font!, .foregroundColor: textColor!])
attString.setAttributes([.font:fontSuper!,.baselineOffset:15, .foregroundColor: textColor!,], range: NSRange(location:1,length:1))
button.setAttributedTitle(attString, for: .normal)
}
I am setting the color based on the logic I have and then set the attributed string color accordingly.

Label top alignment

I'm trying to put the temperature in my app. I would like to show it like that:
But all I'm able to get is that:
I have tried to use this code to align the two label on top:
#IBDesignable class TopAlignedLabel: UILabel {
override func drawText(in rect: CGRect) {
if let stringText = text {
let stringTextAsNSString = stringText as NSString
let labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width,height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size
super.drawText(in: CGRect(x:0,y: 0,width: self.frame.width, height:ceil(labelStringSize.height)))
} else {
super.drawText(in: rect)
}
}
}
It worked on for the '°C' but it's not working for the 25. Can someone help me find a solution to my problem ?
A very simple way to solve this is with attributed strings:
let tempText = "25˚C"
let baseFont = UIFont.systemFont(ofSize: 23.0)!
let superscriptFont = UIFont.systemFont(ofSize: 15.0)!
let attrStr = NSMutableAttributedString(string: tempText, attributes: [NSFontAttributeName: baseFont])
attrStr.addAttributes([NSFontAttributeName: superscriptFont, NSBaselineOffsetAttributeName: 10.0], range: NSMakeRange(2,2))
myLabel.attributedText = attrStr
You can keep adding more different attributes on any range you want by using the addAttributes method.
A font has multiple characteristics, including Ascender, Descender, CapHeight, etc... So what your code gets is not a way to align the character glyphs flush with the top of the label frame, but rather it aligns the Font bounding box to the top of the frame.
Calculating the offset between font metrics might give you what you're after. Here is one example (you can run it in a Playground page):
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let labelOne: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 60.0)
label.text = "25"
label.backgroundColor = .cyan
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 1
label.textAlignment = .right
return label
}()
let labelTwo: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 24.0)
label.text = "°C"
label.backgroundColor = .cyan
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 1
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
// add the scroll view to self.view
self.view.addSubview(labelOne)
self.view.addSubview(labelTwo)
// constrain the scroll view to 8-pts on each side
labelOne.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
labelOne.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
labelTwo.leftAnchor.constraint(equalTo: labelOne.rightAnchor, constant: 2.0).isActive = true
if let f1 = labelOne.font, let f2 = labelTwo.font {
let offset = (f1.ascender - f1.capHeight) - (f2.ascender - f2.capHeight)
labelTwo.topAnchor.constraint(equalTo: labelOne.topAnchor, constant: offset).isActive = true
}
}
}
let vc = TestViewController()
vc.view.backgroundColor = .yellow
PlaygroundPage.current.liveView = vc
And this is the result:
Depending on what font you are actually using, though, that may not be good enough. If so, you'll want to look into CoreText / CTFont / CTFontGetGlyphsForCharacters() / etc.

How to set label height for auto adjust in Read More/Less with Swift 3?

I would like to create the paragraph with Read More/Read Less at the end. Here are my codes;
func getLabelHeight(text: String, width: CGFloat, font: UIFont) -> CGFloat {
let lbl = UILabel(frame: .zero)
lbl.frame.size.width = width
lbl.font = font
lbl.numberOfLines = 0
lbl.text = text
lbl.sizeToFit()
lbl.adjustsFontSizeToFitWidth = true
return lbl.frame.size.height
}
#IBAction func btnReadMore(_ sender: Any) {
if isLabelAtMaxHeight {
btnReadmore.setTitle(NSLocalizedString("Read more", comment: ""), for: .normal)
btnReadmore.titleLabel!.font = UIFont (name: "Tharlon", size: 13)
isLabelAtMaxHeight = false
lblReviewHeight.constant = 29
lblReview.font = UIFont (name: "Tharlon", size: 13)
}
else {
btnReadmore.setTitle(NSLocalizedString("Read less", comment: ""), for: .normal)
btnReadmore.titleLabel!.font = UIFont (name: "Tharlon", size: 13)
isLabelAtMaxHeight = true
lblReviewHeight.constant = getLabelHeight(text: lblReview.text!, width: view.bounds.width, font: lblReview.font)
lblReview.font = UIFont (name: "Tharlon", size: 13)
lblReview.lineBreakMode = NSLineBreakMode.byTruncatingHead
}
}
I also set the label "Word wrap" in Attributes Inspector.
The problem is that when I add "NSLineBreakMode.byTruncatingHead" in Read Less part, all the texts show completely. But, some words in those places inside text disappear.
So, I remove that code and run the app. At that time, texts are not shown completely and only show half. I've been trying to solve this problem the whole day.
I don't want to use any other library.
Could anyone help me please?
Remove constraint lblReviewHeight, then just try to use numberOfLines control your text layout, if your want show all description set numberOfLines = 0, otherwise set numberOfLines to the line you want.
to calculate text height by font and width you can use this extension
extension UIFont {
func sizeOfString (_ string: String, constrainedToWidth width: CGFloat) -> CGSize {
return NSString(string: string).boundingRect(with: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude),
options: NSStringDrawingOptions.usesLineFragmentOrigin,
attributes: [NSFontAttributeName: self],
context: nil).size
}
}
then call it
let width = 290.0
let textSize = UIFont.systemFont(ofSize: 15).sizeOfString("text", constrainedToWidth: width)

Subclassing UIViewController With NavigationBar Title

I'm trying to subclass a UIViewController with a label (UILabel) set to the title of the navigation bar. Instead of setting a name to self.title, I want to use an attributed string to set the title.
class BasicViewController: UIViewController {
var titleString = ""
func setup() {
//self.title = titleString
let navBar = navigationController!.navigationBar
navBar.barTintColor = UIColor.redColor()
let atext = NSMutableAttributedString(string: titleString)
atext.addAttribute(NSForegroundColorAttributeName, value: UIColor.whiteColor(), range: NSMakeRange(0, atext.length))
atext.addAttribute(NSStrokeColorAttributeName, value: UIColor.yellowColor(), range: NSMakeRange(0, atext.length))
atext.addAttribute(NSStrokeWidthAttributeName, value: NSNumber.init(float: -1.0), range: NSMakeRange(0, atext.length))
let titleLabel:UILabel = UILabel.init(frame: CGRectMake(50, 3, 220, 44))
titleLabel.attributedText = atext
titleLabel.textAlignment = NSTextAlignment.Center
titleLabel.font = UIFont(name: "Helvetica", size: 24.0)
}
}
class HomeViewController: BasicViewController {
override func viewDidLoad() {
super.viewDidLoad()
titleString = "My App"
setup()
}
}
If I run this code, I get an empty title. What am I doing wrong? Thanks.
I don't see where you're setting self.navigationItem.titleView = titleLabel

Resources