I've ported my app to XCode 8 and Swift 3 language syntax. Ever since doing so I've had lots of problems, setting a custom font being my current problem:
var sText = "Hello world, this is some text that I'm going to try to format ok?"
var attText = NSMutableAttributedString(string: sText)
var attrs = [NSFontAttributeName: UIFont(name: "Arial", size: 16)]
attText.addAttributes(attrs, range: NSMakeRange(0, sText.characters.count))
lblLabel1.attributedText = attText
So this code crashes every time with an "unrecognized selector sent to instance". Funny enough, setting other properties (like foreground color) work just fine... Just not fonts. I've tried custom fonts, system fonts, other named fonts... nothing seems to work. Anyone else run into this? Is there something I'm doing wrong here??? This code works fine in XCode 7 and even legacy Swift in XCode 8
Thanks in advance...
James
UIFont(name:) returns an Optional, so you have to unwrap it before use:
var sText = "Hello world, this is some text that I'm going to try to format ok?"
var attText = NSMutableAttributedString(string: sText)
if let arial = UIFont(name: "Arial", size: 16) {
var attrs = [NSFontAttributeName: arial]
attText.addAttributes(attrs, range: NSMakeRange(0, sText.characters.count))
// ...
}
Related
On iOS 12, if one changes the text of a UILabel it resets the text attributes. On iOS 13 however, text attributes such as color, typeface, letter spacing, et cetera are kept when the text is changed. What has changed?
An example:
label.text = "Hello world"
let attributedString = NSMutableAttributedString(string: label.text ?? " ")
attributedString.addAttributes([.foregroundColor: UIColor.red], range: NSRange(location: 0, length: attributedString.length))
label.attributedText = attributedString
label.text = "What's up world" // Text is red on iOS 13, default black on iOS 12.
Seems like from iOS 13, if you set and attribute to the entire text, it will persist! If you don't apply the attribute on the entire range of the text, it behaves like before.
You have some options to get around it:
Not applying it on the entire range (Happens most of the times):
attributedString.addAttributes([
.foregroundColor: UIColor.red,
.backgroundColor: UIColor.green
], range: NSRange(location: 0, length: 3))
Perform a version check (Maybe with a little extension)
#available(iOS 13.0, *)
extension UILabel {
func setTextWithoutAttributes(_ text: String) {
// Get rid of the holding attributes instance as Asperi mentioned or in another way you like
self.attributedText = nil
// Set the text
self.text = text
}
}
You did not reset attributedText, but documentation says - if set, the label ignores the properties above (see below for UILabel.h interface, in obj-c it is more correctly visible):
#property(null_resettable, nonatomic,strong) UIColor *textColor UI_APPEARANCE_SELECTOR; // default is labelColor
...
// the underlying attributed string drawn by the label, if set, the label ignores the properties above.
#property(nullable, nonatomic,copy) NSAttributedString *attributedText API_AVAILABLE(ios(6.0)); // default is nil
so behaves as specified (before it might be a bug, that now is fixed)
The solution of your case should be
label.attributedText = attributedString
...
label.attributedText = nil // << reset to default !!
label.text = "What's up world"
Im trying to set a NSMutableParagraphStyle in the following way:
#IBOutlet weak var headline: UILabel! {
didSet {
let style = NSMutableParagraphStyle()
style.maximumLineHeight = 15
style.lineSpacing = 0
style.alignment = .center
let attributes: [NSAttributedStringKey : Any] = [NSAttributedStringKey.paragraphStyle : style,
NSAttributedStringKey.baselineOffset : 0]
let attributedString = NSMutableAttributedString(string: headline.text!, attributes: attributes)
headline.attributedText = attributedString
}
}
...which doesn't change anything about the appearance of the text on iOS 10.3.2 and .3. It works on iOS 9 and iOS 11.
I've added the baselineOffset which seems to solve the issue for some users (radar) - it doesn't help in my case. Is there any other workaround, or do all the users with 10.3.x now have to live with broken layouts all day?
EDIT:
#Larme I tried this, which doesn't work either:
let attributedString = NSMutableAttributedString(string: headline.text!, attributes: attributes)
attributedString.addAttribute(NSAttributedStringKey.backgroundColor, value: UIColor.blue, range: NSMakeRange(0, 3))
headline.attributedText = attributedString
EDIT: After testing matt's code on both iOS 10.3 and 11 devices, I've come to the conclusion that there's a problem when setting the line spacing and max height - setting text alignment works without restrictions. Even when not doing anything in code and just using the Xcode UI to set up my attributed text, I end up with the following result (notice the line spacing):
iOS 11 Device
iOS 10.3.3 Device
No. this is definitely a bug that I see no possible way of working around of short of getting apple to patch it.
I'm sorry :(
Im trying to make a custom font using attributed string for custom UIButton in xcode using swift 2.0
However it works fine in interface builder but not working in any device or simulator, I'm using xcode 7.3 latest with ios 9.3 but unfortunately it seems a bug in xcode/ios. After searching it from google, I came to realize that its should be treat programatically with swift.
My goal is to just put custom font with NSRange such that I have attributed string of ABCDEF with new line after each alphabet. And I just need to setup the Custom font for first two elements via swift. Below is the example
A <--- font1
B <--- fontMiddle
CDEF <--- font1
P.S: I need exact font size and color which is set in interface builder and just want to set the custom readable font for swift
Here's my try:
let size = (tryButton?.titleLabel?.font?.pointSize)!
let labelFont = UIFont(name: "font1", size: size)
let middleFont = UIFont(name: "fontMiddle", size: size)
let attributedString = NSMutableAttributedString(string:(tryButton.titleLabel?.text)!)
attributedString.addAttribute(NSFontAttributeName, value: labelFont!, range: NSRange(location: 0, length: 1) )
attributedString.addAttribute(NSFontAttributeName, value: middleFont!, range: NSRange(location: 1, length: 2) )
attributedString.addAttribute(NSFontAttributeName, value: labelFont!, range: NSRange(location: 2, length: attributedString.lenght) )
tryButton.setAttributedTitle(attributedString, forState: .Normal)
I've read around for different solutions but nothing seems to work. This code creates a nil exception:
[NSFontAttributeName: UIFont(name: "Raleway-SemiBold", size: 16)!]
I have the fonts installed properly and they show up correctly in the app (target is set).
I tried to add the application provided fonts in the plist but nothing happened. I can't edit the items in the array: (they are item0 : string : Raleway-SemiBold.tff).
So basically I'm stuck... Sometimes Swift and Apple environments are great for a programmer, other times (most of the time), they are sooo faulty and need so many workarounds to reach the expected results.
Many thanks in advance for any help.
You're getting an exception because UIFont(name: "Raleway-SemiBold", size: 16) returns nil and you're force-unwrapping it with !.
Instead, use conditional unwrapping:
if let font = UIFont(name: "Raleway-SemiBold", size: 16) {
let attributes = [NSFontAttributeName: font]
// do something with attributes
} else {
// The font "Raleway-SemiBold" is not found
}
You can use UIFont's familyNames() and fontNamesForFamilyName(_:) methods to get the exact string required.
Swift 4
if let font = UIFont(name: "Raleway-SemiBold", size: 16) {
let attributes = [NSAttributedStringKey.font: font]
// do something with attributes
} else {
// The font "Raleway-SemiBold" is not found
}
You Just have to write the correct string name of your font.
Don't write the name that is font file name. (like bodoni-mt-bold.ttf its the file name i have downloaded from any site).
To find out the exact font name follow the image below.
Go to your label select it and go to custom font and then see the name of your custom font in its family. if your custom font name is there then copy that name and past it as a string where u wanna use it. (Note you can't copy font name text you have to write else where then past it)
For Swift 3, here's an update that worked for me:
First you'll set up the font and then create a textAttribute with the NSFontAttributeName:
let font = UIFont(name: "Raleway-SemiBold", size: 16)
textAttribute = [NSFontAttributeName: font as Any, NSForegroundColorAttributeName: UIColor.black]
You can then apply textAttribute to your label, textfield etc.
I'm trying to apply two attributes to a string, one for kerning (NSKernAttributeName) and one for the font (NSFontAttributeName). Although I've checked and rechecked 1000 times, I can only get the kerning attribute to be applied to the string. Here's my setup:
let runAtTitle = "RUN AT"
var attRunAt = NSMutableAttributedString(string: runAtTitle)
let font = UIFont(name: "HelveticaNeue-Bold", size: 76.0)!
let attrs = [NSFontAttributeName: font, NSKernAttributeName: -3.0]
attRunAt.addAttributes(attrs, range: NSMakeRange(0, attRunAt.length))
runAtLabel.attributedText = attRunAt
When I build the app, the kerning is applied to my string, but the font is not. It uses the default 12pt Helvetica. Please tell me I'm doing something wrong.
I just tried your code in Playground and it works fine. Most likely you are setting the text attribute of the label after setting the attributedText. That will revert the string to the normal label string with its attributes, or perhaps for some strange reason keep the kern attribute.
Here is what I get with your code:
and after adding
label.text = "RUN AT"