I\'m moving from swift 3 to swift 4. I have UILabels that I am giving very specific text properties to the label. I\'m getting an \'unexpectedly found nil while unwrapping
@Larme's comment about the .rawValue
not being needed is correct.
Also, you can avoid the force cast that crashes your code using explicit typing:
let strokeTextAttributes: [NSAttributedString.Key: Any] = [
.strokeColor : UIColor.black,
.foregroundColor : UIColor.white,
.strokeWidth : -2.0,
.font : UIFont.boldSystemFont(ofSize: 18)
]
This gets rid of the repetitive NSAttributedString.Key.
, too.
In Swift 4.0+
, attributed string accepts json (dictionary) with key type NSAttributedStringKey
or NSAttributedString.Key
.
So you must change it from [String : Any]
to
Swift 4.1 & below - [NSAttributedStringKey : Any]
&
Swift 4.2 & above - [NSAttributedString.Key : Any]
Initialiser for AttributedString
in Swift 4.2 is changed to [NSAttributedString.Key : Any]?
public init(string str: String, attributes attrs: [NSAttributedString.Key : Any]? = nil)
Here is sample working code.
let label = UILabel()
let labelText = "String Text"
let strokeTextAttributes = [
NSAttributedString.Key.strokeColor : UIColor.black,
NSAttributedString.Key.foregroundColor : UIColor.white,
NSAttributedString.Key.strokeWidth : -2.0,
NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 18)
] as [NSAttributedString.Key : Any]
label.attributedText = NSAttributedString(string: labelText, attributes: strokeTextAttributes)
Initialiser for AttributedString
in Swift 4.0 is changed to [NSAttributedStringKey : Any]?
.
public init(string str: String, attributes attrs: [NSAttributedStringKey : Any]? = nil)
Here is sample working code.
let label = UILabel()
let labelText = "String Text"
let strokeTextAttributes = [
NSAttributedStringKey.strokeColor : UIColor.black,
NSAttributedStringKey.foregroundColor : UIColor.white,
NSAttributedStringKey.strokeWidth : -2.0,
NSAttributedStringKey.font : UIFont.boldSystemFont(ofSize: 18)
] as [NSAttributedStringKey : Any]
label.attributedText = NSAttributedString(string: labelText, attributes: strokeTextAttributes)
Look at this Apple Document, for more info: NSAttributedString - Creating an NSAttributedString Object
NSAttributedStringKey.strokeColor.rawValue
is of typeString
NSAttributedStringKey.strokeColor
is of typeNSAttributedStringKey
So its unable to convert String
to NSAttributedStringKey
.
You have to use like below:
let strokeTextAttributes: [NSAttributedStringKey : Any] = [
NSAttributedStringKey.strokeColor : UIColor.black,
NSAttributedStringKey.foregroundColor : UIColor.white,
NSAttributedStringKey.strokeWidth : -2.0,
NSAttributedStringKey.font : UIFont.boldSystemFont(ofSize: 18)
]
Swift 4 Attributed text with multiple colors
extension NSMutableAttributedString
{
@discardableResult func DustyOrange(_ text: String, Fontsize : CGFloat) -> NSMutableAttributedString
{
let attrs: [NSAttributedStringKey: Any] = [.font: UIFont(name: "SFUIDisplay-Regular", size: Fontsize)!, NSAttributedStringKey.foregroundColor: UIColor(red: 242.0/255.0, green: 97.0/255.0, blue: 0.0/255.0, alpha: 1.0) ]
let boldString = NSMutableAttributedString(string:text, attributes: attrs)
append(boldString)
return self
}
@discardableResult func WarmGrey(_ text: String, Fontsize : CGFloat) -> NSMutableAttributedString {
let attrs: [NSAttributedStringKey: Any] = [.font: UIFont(name: "SFUIDisplay-Regular", size: Fontsize)!, NSAttributedStringKey.foregroundColor: UIColor(red: 152.0/255.0, green: 152.0/255.0, blue: 152.0/255.0, alpha: 1.0) ]
let boldString = NSMutableAttributedString(string:text, attributes: attrs)
append(boldString)
return self
}
}
Now you can Execute the function something like this to use as a globally
func FormattedString(Orange : String, WarmGrey : String ,fontsize : CGFloat) -> NSMutableAttributedString
{
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .left
paragraphStyle.lineSpacing = 1
paragraphStyle.paragraphSpacing = 1
let formattedString = NSMutableAttributedString()
formattedString
.DustyOrange(Orange, Fontsize: fontsize)
.WarmGrey(WarmGrey, Fontsize: fontsize )
formattedString.addAttributes([NSAttributedStringKey.paragraphStyle: paragraphStyle], range: NSRange(location: 0, length: formattedString.length))
return formattedString
}
You can use globalized function like this
yourLabelName.attributedText = FormattedString(Orange: "String with orange color", WarmGrey: " String with warm grey color.", fontsize: 11.5)
Attributed text with image
func AttributedTextwithImgaeSuffix(AttributeImage : UIImage , AttributedText : String , buttonBound : UIButton) -> NSMutableAttributedString
{
let fullString = NSMutableAttributedString(string: AttributedText + " ")
let image1Attachment = NSTextAttachment()
image1Attachment.bounds = CGRect(x: 0, y: ((buttonBound.titleLabel?.font.capHeight)! -
AttributeImage.size.height).rounded() / 2, width:
AttributeImage.size.width, height: AttributeImage.size.height)
image1Attachment.image = AttributeImage
let image1String = NSAttributedString(attachment: image1Attachment)
fullString.append(image1String)
fullString.append(NSAttributedString(string: ""))
return fullString
}
you can use "NSTextAttachment" with your button label like this.
yourUIButton.setAttributedTitle(AttributedTextwithImgaeSuffix(AttributeImage: desiredImage, AttributedText: "desired UIButton title", buttonBound: yourUIButton), for: .normal)
if you want to change particular string value so that below answer is helpful you:-
let subStr = "Hello" let allStr = "Hello World"
let newStr = NSMutableAttributedString(string: allStr)
newStr.addAttribute(kCTFontAttributeName as NSAttributedStringKey, value: UIFont.init(customFont: .MyriadPro_R, withSize: 18)!, range: (allStr as NSString).range(of: subStr))
newStr.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.PrimaryColor, range: (allStr as NSString).range(of: subStr))
self.stateLbl.attributedText = newStr
let text = systolicString + " / " + diastolicString
let newStr = NSMutableAttributedString(string: text)
// I have static ranges, but you can also extract them dynamically
let systolicRange = NSRange(location: 0, length: 2)
let backslashRange = NSRange(location: 3, length: 1)
let diastolicRange = NSRange(location: 5, length: 2)
newStr.addAttribute(NSAttributedStringKey.font, value: UIFont.ubuntuRegular(28), range: systolicRange)
newStr.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor(hexString: "042f57"), range: systolicRange)
newStr.addAttribute(NSAttributedStringKey.font, value: UIFont.ubuntuLight(23), range: backslashRange)
newStr.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor(hexString: "6485a3"), range: backslashRange)
newStr.addAttribute(NSAttributedStringKey.font, value: UIFont.ubuntuRegular(18), range: diastolicRange)
newStr.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor(hexString: "042f57"), range: diastolicRange)
// my UILabel
valueLabel.attributedText = newStr