Swift 4 Conversion error - NSAttributedStringKey: Any - swift4

I converted my app recently and I keep getting the error
"Cannot convert value of type '[String : Any]' to expected argument type '[NSAttributedStringKey: Any]?'
barButtonItem.setTitleTextAttributes(attributes, for: .normal)
Whole code:
class func getBarButtonItem(title:String) -> UIBarButtonItem {
let barButtonItem = UIBarButtonItem.init(title: title, style: .plain, target: nil, action: nil)
let attributes = [NSAttributedStringKey.font.rawValue: UIFont(name: "Helvetica-Bold", size: 15.0)!, NSAttributedStringKey.foregroundColor: UIColor.white] as! [String : Any]
barButtonItem.setTitleTextAttributes(attributes, for: .normal)
return barButtonItem
}

Why you got this error
Previously, your attributes is defined as [String: Any], where the key comes from NSAttributedStringKey as a string or NSAttributedString.Key in Swift 4.2
During the migration, the compiler tries to keep the [String: Any] type. However, NSAttributedStringKey becomes a struct in swift 4. So the compiler tries to change that to string by getting its raw value.
In this case, setTitleTextAttributes is looking for [NSAttributedStringKey: Any] but you provided [String: Any]
To fix this error:
Remove .rawValue and cast your attributes as [NSAttributedStringKey: Any]
Namely, change this following line
let attributes = [NSAttributedStringKey.font.rawValue:
UIFont(name: "Helvetica-Bold", size: 15.0)!,
NSAttributedStringKey.foregroundColor: UIColor.white] as! [String : Any]
to
let attributes = [NSAttributedStringKey.font:
UIFont(name: "Helvetica-Bold", size: 15.0)!,
NSAttributedStringKey.foregroundColor: UIColor.white] as! [NSAttributedStringKey: Any]
And in Swift 4.2,
let attributes = [NSAttributedString.Key.font:
UIFont(name: "Helvetica-Bold", size: 15.0)!,
NSAttributedString.Key.foregroundColor: UIColor.white] as! [NSAttributedStringKey: Any]

Its expecting NSAttributedStringKey(NSAttributedStringKey.font) and you are sending String(NSAttributedStringKey.font.rawValue).
So please replace NSAttributedStringKey.font.rawValue with NSAttributedStringKey.font like below :
let attributes = [NSAttributedStringKey.font: UIFont(name: "Helvetica-Bold", size: 15.0)!, NSAttributedStringKey.foregroundColor: UIColor.white]

As noted in previous answers, NSAttributedStringKey was changed to a struct in Swift 4. However, other objects that use NSAttributedStringKey apparently didn't get updated at the same time.
The easiest fix, without having to change any of your other code, is to append .rawValue to all your occurrences of NSAttributedStringKey setters - turning the key names into Strings:
let attributes = [
NSAttributedStringKey.font.rawValue: UIFont(name: "Helvetica-Bold", size: 15.0)!,
NSAttributedStringKey.foregroundColor.rawValue: UIColor.white
] as [String : Any]
Note that you won't need the ! at the as now, either.
Alternatively, you can skip the as cast at the end by declaring the array to be [String : Any] upfront:
let attributes: [String : Any] = [
NSAttributedStringKey.font.rawValue: UIFont(name: "Helvetica-Bold", size: 15.0)!,
NSAttributedStringKey.foregroundColor.rawValue: UIColor.white
]
Of course, you still need to append the .rawValue for each NSAttributedStringKey item you set.

leanne's answer is correct for the cases where you still need to use [String : Any] and not [NSAttributedStringKey : Any].
For example, in UIKit UITextView.typingAttributes is still of type [String : Any]. So for that property you have to use converted attributes (including custom ones):
let customAttributeName = "MyCustomAttributeName"
let customValue: CGFloat = 15.0
let normalTextAttributes: [NSAttributedStringKey : Any] =
[NSAttributedStringKey.font : UIFont.systemFont(ofSize: 14.0),
NSAttributedStringKey.foregroundColor : UIColor.blue,
NSAttributedStringKey.backgroundColor : UIColor.clear,
NSAttributedStringKey(rawValue: customAttributeName): customValue]
textView.typingAttributes = normalTextAttributes.toTypingAttributes()
where toTypingAttributes() is a function defined by extension in any of your project files:
extension Dictionary where Key == NSAttributedStringKey {
func toTypingAttributes() -> [String: Any] {
var convertedDictionary = [String: Any]()
for (key, value) in self {
convertedDictionary[key.rawValue] = value
}
return convertedDictionary
}

Related

How to initialise a let text attribute

I have a text attribute for a foreground colour which I want to use in attributed strings. The attribute is a let constant in my class and I want to initialise it with a UIColor which I pass into the init for the class.
class LocationOptions {
let live : NSAttributedString.Key!
let black = [NSAttributedString.Key.foregroundColor: UIColor.black]
let grey = [NSAttributedString.Key.foregroundColor: UIColor.gray]
let findingLocation: NSAttributedString!
let centralLondon: NSAttributedString!
let allLondon: NSAttributedString!
init(color: UIColor){
live = [NSAttributedString.Key.foregroundColor: color]
findingLocation = NSAttributedString(string: "Finding Location...", attributes: grey)
centralLondon = NSAttributedString(string: "Central London", attributes: black)
allLondon = NSAttributedString(string: "All London", attributes: black)
}
....
With this code the compiler comes up with the error when I assign live:
Cannot assign value of type '[NSAttributedString.Key : UIColor]' to type 'NSAttributedString.Key'
If I change the declaration of live to
let live: NSAttributedString.Key.foregroundColor!
The compiler comes up with the error when I declare live:
Static let 'foregroundColor' is not a member type of 'NSAttributedString.Key'
How do I initialise a text attribute like this?
That is because it needs attribute dictionary.
//This is only key and you cannot assign a attribute to it
let live = NSAttributedString.Key!
//this is only value
let live: NSAttributedString.Key.foregroundColor!
These won't work. The way you would make them work is as follow:
class LocationOptions {
let live: [NSAttributedString.Key : Any]
init(color: UIColor) {
live = [NSAttributedString.Key.foregroundColor: color]
}
}
The problem is here…
let live : NSAttributedString.Key!
live is type NSAttributedString.Key!, but you're assigning a Dictionary to it.
If live is a colour use:
let live : UIColor
if it's a dictionary of Attributes, use:
let live : [NSAttributedString.Key: Any]
Just declare live as
let live: [NSAttributedString.Key : UIColor]!
NSAttributedString.Key.foregroundColor! cannot be the type for live because it is not a type, it is a property. By declaring live as [NSAttributedString.Key : UIColor], you can assign the dictionary to it while being able to initialize the NSAttributedString in a simpler way.

UIAlertController private API usage?

Was the following code safe to use to create an UIAlertController :
let titleFont:[String : AnyObject] = [ NSFontAttributeName : UIFont(name: "AmericanTypewriter", size: 18)! ]
let messageFont:[String : AnyObject] = [ NSFontAttributeName : UIFont(name: "HelveticaNeue-Thin", size: 14)! ]
let attributedTitle = NSMutableAttributedString(string: "Multiple buttons", attributes: titleFont)
let attributedMessage = NSMutableAttributedString(string: "Select an Action", attributes: messageFont)
alert.setValue(attributedTitle, forKey: "attributedTitle")
alert.setValue(attributedMessage, forKey: "attributedMessage")
I heard that setting TextAttributes to UIAlertController font was not safe to use and it touched private API.So, it might get rejected.
And TutPlus+ posted tutorial like that. I just want to be sure. My above question doesn't mean anything to TutPlus. It was only a question about private APIs. I just want to be sure that if I use that code, will I get rejected or not.

cannot convert value of type [anyhashable: any] to [string: any]

let darkGray = UIColor.darkGray
let lightGray = UIColor.lightGray
let white = UIColor.white
// Navigation bar background.
UINavigationBar.appearance().barTintColor = darkGray
UINavigationBar.appearance().tintColor = lightGray
// Color of typed text in the search bar.
let searchBarTextAttributes: [AnyHashable: Any] = [NSForegroundColorAttributeName: lightGray, NSFontAttributeName: UIFont.systemFont(ofSize: CGFloat(UIFont.systemFontSize))]
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = searchBarTextAttributes as! [String : Any]
// Color of the placeholder text in the search bar prior to text entry.
let placeholderAttributes: [AnyHashable: Any] = [NSForegroundColorAttributeName: white, NSFontAttributeName: UIFont.systemFont(ofSize: CGFloat(UIFont.systemFontSize))]
// Color of the default search text.
// NOTE: In a production scenario, "Search" would be a localized string.
let attributedPlaceholder = NSAttributedString( string: "Search", attributes: placeholderAttributes)
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).attributedPlaceholder = attributedPlaceholder
In the let attributedPlaceholder I'm coming up with an error, wondering if someone could shed some light on this for me?
let placeholderAttributes: [AnyHashable: Any] = [NSForegroundColorAttributeName: UIColor.white, NSFontAttributeName: UIFont.systemFont(ofSize: CGFloat(UIFont.systemFontSize))]
// Color of the default search text.
// NOTE: In a production scenario, "Search" would be a localized string.
let attributedPlaceholder = NSAttributedString( string: "Lookup", attributes: placeholderAttributes as? [String: Any])
This worked for me, thanks.
Can replace your code with this:
let placeholderAttributes = ["NSForegroundColorAttributeName": UIColor.white, "NSFontAttributeName": UIFont.systemFont(ofSize: CGFloat(UIFont.systemFontSize))]
// equivalent of: let placeholderAttributes: [String: Any?] = ...
let attributedPlaceholder = NSAttributedString( string: "Search", attributes: placeholderAttributes)
Because you cannot convert AnyHashable to String, or [AnyHashable:Any?] to [String:Any?], in this case.

Is there a simple way to make text in a variable bold in Swift? [duplicate]

I am trying to make a simple Coffee Calculator. I need to display the amount of coffee in grams. The "g" symbol for grams needs to be attached to my UILabel that I am using to display the amount. The numbers in the UILabel are changing dynamically with user input just fine, but I need to add a lower case "g" on the end of the string that is formatted differently from the updating numbers. The "g" needs to be attached to the numbers so that as the number size and position changes, the "g" "moves" with the numbers. I'm sure this problem has been solved before so a link in the right direction would be helpful as I've googled my little heart out.
I've searched through the documentation for an attributed string and I even downloded an "Attributed String Creator" from the app store, but the resulting code is in Objective-C and I am using Swift. What would be awesome, and probably helpful to other developers learning this language, is a clear example of creating a custom font with custom attributes using an attributed string in Swift. The documentation for this is very confusing as there is not a very clear path on how to do so. My plan is to create the attributed string and add it to the end of my coffeeAmount string.
var coffeeAmount: String = calculatedCoffee + attributedText
Where calculatedCoffee is an Int converted to a string and "attributedText" is the lowercase "g" with customized font that I am trying to create. Maybe I'm going about this the wrong way. Any help is appreciated!
This answer has been updated for Swift 4.2.
Quick Reference
The general form for making and setting an attributed string is like this. You can find other common options below.
// create attributed string
let myString = "Swift Attributed String"
let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
// set attributed text on a UILabel
myLabel.attributedText = myAttrString
let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]
let myAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
let myAttribute = [ NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 18.0)! ]
let myAttribute = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue ]
let myShadow = NSShadow()
myShadow.shadowBlurRadius = 3
myShadow.shadowOffset = CGSize(width: 3, height: 3)
myShadow.shadowColor = UIColor.gray
let myAttribute = [ NSAttributedString.Key.shadow: myShadow ]
The rest of this post gives more detail for those who are interested.
Attributes
String attributes are just a dictionary in the form of [NSAttributedString.Key: Any], where NSAttributedString.Key is the key name of the attribute and Any is the value of some Type. The value could be a font, a color, an integer, or something else. There are many standard attributes in Swift that have already been predefined. For example:
key name: NSAttributedString.Key.font, value: a UIFont
key name: NSAttributedString.Key.foregroundColor, value: a UIColor
key name: NSAttributedString.Key.link, value: an NSURL or NSString
There are many others. See this link for more. You can even make your own custom attributes like:
key name: NSAttributedString.Key.myName, value: some Type.
if you make an extension:
extension NSAttributedString.Key {
static let myName = NSAttributedString.Key(rawValue: "myCustomAttributeKey")
}
Creating attributes in Swift
You can declare attributes just like declaring any other dictionary.
// single attributes declared one at a time
let singleAttribute1 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let singleAttribute2 = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
let singleAttribute3 = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue ]
// multiple attributes declared at once
let multipleAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.foregroundColor: UIColor.green,
NSAttributedString.Key.backgroundColor: UIColor.yellow,
NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue ]
// custom attribute
let customAttribute = [ NSAttributedString.Key.myName: "Some value" ]
Note the rawValue that was needed for the underline style value.
Because attributes are just Dictionaries, you can also create them by making an empty Dictionary and then adding key-value pairs to it. If the value will contain multiple types, then you have to use Any as the type. Here is the multipleAttributes example from above, recreated in this fashion:
var multipleAttributes = [NSAttributedString.Key : Any]()
multipleAttributes[NSAttributedString.Key.foregroundColor] = UIColor.green
multipleAttributes[NSAttributedString.Key.backgroundColor] = UIColor.yellow
multipleAttributes[NSAttributedString.Key.underlineStyle] = NSUnderlineStyle.double.rawValue
Attributed Strings
Now that you understand attributes, you can make attributed strings.
Initialization
There are a few ways to create attributed strings. If you just need a read-only string you can use NSAttributedString. Here are some ways to initialize it:
// Initialize with a string only
let attrString1 = NSAttributedString(string: "Hello.")
// Initialize with a string and inline attribute(s)
let attrString2 = NSAttributedString(string: "Hello.", attributes: [NSAttributedString.Key.myName: "A value"])
// Initialize with a string and separately declared attribute(s)
let myAttributes1 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let attrString3 = NSAttributedString(string: "Hello.", attributes: myAttributes1)
If you will need to change the attributes or the string content later, you should use NSMutableAttributedString. The declarations are very similar:
// Create a blank attributed string
let mutableAttrString1 = NSMutableAttributedString()
// Initialize with a string only
let mutableAttrString2 = NSMutableAttributedString(string: "Hello.")
// Initialize with a string and inline attribute(s)
let mutableAttrString3 = NSMutableAttributedString(string: "Hello.", attributes: [NSAttributedString.Key.myName: "A value"])
// Initialize with a string and separately declared attribute(s)
let myAttributes2 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let mutableAttrString4 = NSMutableAttributedString(string: "Hello.", attributes: myAttributes2)
Changing an Attributed String
As an example, let's create the attributed string at the top of this post.
First create an NSMutableAttributedString with a new font attribute.
let myAttribute = [ NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 18.0)! ]
let myString = NSMutableAttributedString(string: "Swift", attributes: myAttribute )
If you are working along, set the attributed string to a UITextView (or UILabel) like this:
textView.attributedText = myString
You don't use textView.text.
Here is the result:
Then append another attributed string that doesn't have any attributes set. (Notice that even though I used let to declare myString above, I can still modify it because it is an NSMutableAttributedString. This seems rather unSwiftlike to me and I wouldn't be surprised if this changes in the future. Leave me a comment when that happens.)
let attrString = NSAttributedString(string: " Attributed Strings")
myString.append(attrString)
Next we'll just select the "Strings" word, which starts at index 17 and has a length of 7. Notice that this is an NSRange and not a Swift Range. (See this answer for more about Ranges.) The addAttribute method lets us put the attribute key name in the first spot, the attribute value in the second spot, and the range in the third spot.
var myRange = NSRange(location: 17, length: 7) // range starting at location 17 with a lenth of 7: "Strings"
myString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red, range: myRange)
Finally, let's add a background color. For variety, let's use the addAttributes method (note the s). I could add multiple attributes at once with this method, but I will just add one again.
myRange = NSRange(location: 3, length: 17)
let anotherAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
myString.addAttributes(anotherAttribute, range: myRange)
Notice that the attributes are overlapping in some places. Adding an attribute doesn't overwrite an attribute that is already there.
Related
How to change the text of an NSMutableAttributedString but keep the attributes
Further Reading
How to retrieve the attributes from a tap location
Attributed String Programming Guide (very informative but unfortunately only in Objective-C)
Swift uses the same NSMutableAttributedString that Obj-C does. You instantiate it by passing in the calculated value as a string:
var attributedString = NSMutableAttributedString(string:"\(calculatedCoffee)")
Now create the attributed g string (heh). Note: UIFont.systemFontOfSize(_) is now a failable initializer, so it has to be unwrapped before you can use it:
var attrs = [NSFontAttributeName : UIFont.systemFontOfSize(19.0)!]
var gString = NSMutableAttributedString(string:"g", attributes:attrs)
And then append it:
attributedString.appendAttributedString(gString)
You can then set the UILabel to display the NSAttributedString like this:
myLabel.attributedText = attributedString
I would highly recommend using a library for attributed strings. It makes it much easier when you want, for example, one string with four different colors and four different fonts. Here is my favorite. It is called SwiftyAttributes
If you wanted to make a string with four different colors and different fonts using SwiftyAttributes:
let magenta = "Hello ".withAttributes([
.textColor(.magenta),
.font(.systemFont(ofSize: 15.0))
])
let cyan = "Sir ".withAttributes([
.textColor(.cyan),
.font(.boldSystemFont(ofSize: 15.0))
])
let green = "Lancelot".withAttributes([
.textColor(.green),
.font(.italicSystemFont(ofSize: 15.0))
])
let blue = "!".withAttributes([
.textColor(.blue),
.font(.preferredFont(forTextStyle: UIFontTextStyle.headline))
])
let finalString = magenta + cyan + green + blue
finalString would show as
Xcode 6 version:
let attriString = NSAttributedString(string:"attriString", attributes:
[NSForegroundColorAttributeName: UIColor.lightGrayColor(),
NSFontAttributeName: AttriFont])
Xcode 9.3 version:
let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedStringKey.foregroundColor: UIColor.lightGray,
NSAttributedStringKey.font: AttriFont])
Xcode 10, iOS 12, Swift 4:
let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedString.Key.foregroundColor: UIColor.lightGray,
NSAttributedString.Key.font: AttriFont])
Swift 4:
let attributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 17)!,
NSAttributedStringKey.foregroundColor: UIColor.white]
Swift 5
let attrStri = NSMutableAttributedString.init(string:"This is red")
let nsRange = NSString(string: "This is red")
.range(of: "red", options: String.CompareOptions.caseInsensitive)
attrStri.addAttributes([
NSAttributedString.Key.foregroundColor : UIColor.red,
NSAttributedString.Key.font: UIFont.init(name: "PTSans-Regular", size: 15.0) as Any
], range: nsRange)
self.label.attributedText = attrStri
Swift: xcode 6.1
let font:UIFont? = UIFont(name: "Arial", size: 12.0)
let attrString = NSAttributedString(
string: titleData,
attributes: NSDictionary(
object: font!,
forKey: NSFontAttributeName))
Details
Swift 5.2, Xcode 11.4 (11E146)
Solution
protocol AttributedStringComponent {
var text: String { get }
func getAttributes() -> [NSAttributedString.Key: Any]?
}
// MARK: String extensions
extension String: AttributedStringComponent {
var text: String { self }
func getAttributes() -> [NSAttributedString.Key: Any]? { return nil }
}
extension String {
func toAttributed(with attributes: [NSAttributedString.Key: Any]?) -> NSAttributedString {
.init(string: self, attributes: attributes)
}
}
// MARK: NSAttributedString extensions
extension NSAttributedString: AttributedStringComponent {
var text: String { string }
func getAttributes() -> [Key: Any]? {
if string.isEmpty { return nil }
var range = NSRange(location: 0, length: string.count)
return attributes(at: 0, effectiveRange: &range)
}
}
extension NSAttributedString {
convenience init?(from attributedStringComponents: [AttributedStringComponent],
defaultAttributes: [NSAttributedString.Key: Any],
joinedSeparator: String = " ") {
switch attributedStringComponents.count {
case 0: return nil
default:
var joinedString = ""
typealias SttributedStringComponentDescriptor = ([NSAttributedString.Key: Any], NSRange)
let sttributedStringComponents = attributedStringComponents.enumerated().flatMap { (index, component) -> [SttributedStringComponentDescriptor] in
var components = [SttributedStringComponentDescriptor]()
if index != 0 {
components.append((defaultAttributes,
NSRange(location: joinedString.count, length: joinedSeparator.count)))
joinedString += joinedSeparator
}
components.append((component.getAttributes() ?? defaultAttributes,
NSRange(location: joinedString.count, length: component.text.count)))
joinedString += component.text
return components
}
let attributedString = NSMutableAttributedString(string: joinedString)
sttributedStringComponents.forEach { attributedString.addAttributes($0, range: $1) }
self.init(attributedString: attributedString)
}
}
}
Usage
let defaultAttributes = [
.font: UIFont.systemFont(ofSize: 16, weight: .regular),
.foregroundColor: UIColor.blue
] as [NSAttributedString.Key : Any]
let marketingAttributes = [
.font: UIFont.systemFont(ofSize: 20.0, weight: .bold),
.foregroundColor: UIColor.black
] as [NSAttributedString.Key : Any]
let attributedStringComponents = [
"pay for",
NSAttributedString(string: "one",
attributes: marketingAttributes),
"and get",
"three!\n".toAttributed(with: marketingAttributes),
"Only today!".toAttributed(with: [
.font: UIFont.systemFont(ofSize: 16.0, weight: .bold),
.foregroundColor: UIColor.red
])
] as [AttributedStringComponent]
let attributedText = NSAttributedString(from: attributedStringComponents, defaultAttributes: defaultAttributes)
Full Example
do not forget to paste the solution code here
import UIKit
class ViewController: UIViewController {
private weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: .init(x: 40, y: 40, width: 300, height: 80))
label.numberOfLines = 2
view.addSubview(label)
self.label = label
let defaultAttributes = [
.font: UIFont.systemFont(ofSize: 16, weight: .regular),
.foregroundColor: UIColor.blue
] as [NSAttributedString.Key : Any]
let marketingAttributes = [
.font: UIFont.systemFont(ofSize: 20.0, weight: .bold),
.foregroundColor: UIColor.black
] as [NSAttributedString.Key : Any]
let attributedStringComponents = [
"pay for",
NSAttributedString(string: "one",
attributes: marketingAttributes),
"and get",
"three!\n".toAttributed(with: marketingAttributes),
"Only today!".toAttributed(with: [
.font: UIFont.systemFont(ofSize: 16.0, weight: .bold),
.foregroundColor: UIColor.red
])
] as [AttributedStringComponent]
label.attributedText = NSAttributedString(from: attributedStringComponents, defaultAttributes: defaultAttributes)
label.textAlignment = .center
}
}
Result
The best way to approach Attributed Strings on iOS is by using the built-in Attributed Text editor in the interface builder and avoid uneccessary hardcoding NSAtrributedStringKeys in your source files.
You can later dynamically replace placehoderls at runtime by using this extension:
extension NSAttributedString {
func replacing(placeholder:String, with valueString:String) -> NSAttributedString {
if let range = self.string.range(of:placeholder) {
let nsRange = NSRange(range,in:valueString)
let mutableText = NSMutableAttributedString(attributedString: self)
mutableText.replaceCharacters(in: nsRange, with: valueString)
return mutableText as NSAttributedString
}
return self
}
}
Add a storyboard label with attributed text looking like this.
Then you simply update the value each time you need like this:
label.attributedText = initalAttributedString.replacing(placeholder: "<price>", with: newValue)
Make sure to save into initalAttributedString the original value.
You can better understand this approach by reading this article:
https://medium.com/mobile-appetite/text-attributes-on-ios-the-effortless-approach-ff086588173e
Swift 2.0
Here is a sample:
let newsString: NSMutableAttributedString = NSMutableAttributedString(string: "Tap here to read the latest Football News.")
newsString.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleDouble.rawValue], range: NSMakeRange(4, 4))
sampleLabel.attributedText = newsString.copy() as? NSAttributedString
Swift 5.x
let newsString: NSMutableAttributedString = NSMutableAttributedString(string: "Tap here to read the latest Football News.")
newsString.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue], range: NSMakeRange(4, 4))
sampleLabel.attributedText = newsString.copy() as? NSAttributedString
OR
let stringAttributes = [
NSFontAttributeName : UIFont(name: "Helvetica Neue", size: 17.0)!,
NSUnderlineStyleAttributeName : 1,
NSForegroundColorAttributeName : UIColor.orangeColor(),
NSTextEffectAttributeName : NSTextEffectLetterpressStyle,
NSStrokeWidthAttributeName : 2.0]
let atrributedString = NSAttributedString(string: "Sample String: Attributed", attributes: stringAttributes)
sampleLabel.attributedText = atrributedString
I created an online tool that is going to solve your problem! You can write your string and apply styles graphically and the tool gives you objective-c and swift code to generate that string.
Also is open source so feel free to extend it and send PRs.
Transformer Tool
Github
Works well in beta 6
let attrString = NSAttributedString(
string: "title-title-title",
attributes: NSDictionary(
object: NSFont(name: "Arial", size: 12.0),
forKey: NSFontAttributeName))
Swift 5 and above
let attributedString = NSAttributedString(string:"targetString",
attributes:[NSAttributedString.Key.foregroundColor: UIColor.lightGray,
NSAttributedString.Key.font: UIFont(name: "Arial", size: 18.0) as Any])
func decorateText(sub:String, des:String)->NSAttributedString{
let textAttributesOne = [NSAttributedStringKey.foregroundColor: UIColor.darkText, NSAttributedStringKey.font: UIFont(name: "PTSans-Bold", size: 17.0)!]
let textAttributesTwo = [NSAttributedStringKey.foregroundColor: UIColor.black, NSAttributedStringKey.font: UIFont(name: "PTSans-Regular", size: 14.0)!]
let textPartOne = NSMutableAttributedString(string: sub, attributes: textAttributesOne)
let textPartTwo = NSMutableAttributedString(string: des, attributes: textAttributesTwo)
let textCombination = NSMutableAttributedString()
textCombination.append(textPartOne)
textCombination.append(textPartTwo)
return textCombination
}
//Implementation
cell.lblFrom.attributedText = decorateText(sub: sender!, des: " - \(convertDateFormatShort3(myDateString: datetime!))")
Swift 4
let attributes = [NSAttributedStringKey.font : UIFont(name: CustomFont.NAME_REGULAR.rawValue, size: CustomFontSize.SURVEY_FORM_LABEL_SIZE.rawValue)!]
let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)
You need to remove the raw value in swift 4
Use this sample code. This is very short code to achieve your requirement. This is working for me.
let attributes = [NSAttributedStringKey.font : UIFont(name: CustomFont.NAME_REGULAR.rawValue, size: CustomFontSize.SURVEY_FORM_LABEL_SIZE.rawValue)!]
let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)
Swift 3,4,5
Use below code for Text Color, Font, Background Color and Underline/Un derline Color
let text = "swift is language"
let attributes = [NSAttributedString.Key.foregroundColor: UIColor.red, NSAttributedString.Key.backgroundColor: UIColor.blue,NSAttributedString.Key.font: UIFont.systemFont(ofSize: 25.0),NSAttributedString.Key.underlineColor: UIColor.white,NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue] as [NSAttributedString.Key : Any]
let textAttribute = NSAttributedString(string: text, attributes: attributes)
swiftLabel1.attributedText = textAttribute
For me above solutions didn't work when setting a specific color or property.
This did work:
let attributes = [
NSFontAttributeName : UIFont(name: "Helvetica Neue", size: 12.0)!,
NSUnderlineStyleAttributeName : 1,
NSForegroundColorAttributeName : UIColor.darkGrayColor(),
NSTextEffectAttributeName : NSTextEffectLetterpressStyle,
NSStrokeWidthAttributeName : 3.0]
var atriString = NSAttributedString(string: "My Attributed String", attributes: attributes)
Swift 2.1 - Xcode 7
let labelFont = UIFont(name: "HelveticaNeue-Bold", size: 18)
let attributes :[String:AnyObject] = [NSFontAttributeName : labelFont!]
let attrString = NSAttributedString(string:"foo", attributes: attributes)
myLabel.attributedText = attrString
I did a function that takes array of strings and returns attributed string with the attributes you give.
func createAttributedString(stringArray: [String], attributedPart: Int, attributes: [NSAttributedString.Key: Any]) -> NSMutableAttributedString? {
let finalString = NSMutableAttributedString()
for i in 0 ..< stringArray.count {
var attributedString = NSMutableAttributedString(string: stringArray[i], attributes: nil)
if i == attributedPart {
attributedString = NSMutableAttributedString(string: attributedString.string, attributes: attributes)
finalString.append(attributedString)
} else {
finalString.append(attributedString)
}
}
return finalString
}
In the example above you specify what part of string you want to get attributed with attributedPart: Int
And then you give the attributes for it with
attributes: [NSAttributedString.Key: Any]
USE EXAMPLE
if let attributedString = createAttributedString(stringArray: ["Hello ", "how ", " are you?"], attributedPart: 2, attributes: [NSAttributedString.Key.foregroundColor: UIColor.systemYellow]) {
myLabel.attributedText = attributedString
}
Will do:
extension UILabel{
func setSubTextColor(pSubString : String, pColor : UIColor){
let attributedString: NSMutableAttributedString = self.attributedText != nil ? NSMutableAttributedString(attributedString: self.attributedText!) : NSMutableAttributedString(string: self.text!);
let range = attributedString.mutableString.range(of: pSubString, options:NSString.CompareOptions.caseInsensitive)
if range.location != NSNotFound {
attributedString.addAttribute(NSForegroundColorAttributeName, value: pColor, range: range);
}
self.attributedText = attributedString
}
}
The attributes can be setting directly in swift 3...
let attributes = NSAttributedString(string: "String", attributes: [NSFontAttributeName : UIFont(name: "AvenirNext-Medium", size: 30)!,
NSForegroundColorAttributeName : UIColor .white,
NSTextEffectAttributeName : NSTextEffectLetterpressStyle])
Then use the variable in any class with attributes
Swift 4.2
extension UILabel {
func boldSubstring(_ substr: String) {
guard substr.isEmpty == false,
let text = attributedText,
let range = text.string.range(of: substr, options: .caseInsensitive) else {
return
}
let attr = NSMutableAttributedString(attributedString: text)
let start = text.string.distance(from: text.string.startIndex, to: range.lowerBound)
let length = text.string.distance(from: range.lowerBound, to: range.upperBound)
attr.addAttributes([NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: self.font.pointSize)],
range: NSMakeRange(start, length))
attributedText = attr
}
}
It will be really easy to solve your problem with the library I created. It is called Atributika.
let calculatedCoffee: Int = 768
let g = Style("g").font(.boldSystemFont(ofSize: 12)).foregroundColor(.red)
let all = Style.font(.systemFont(ofSize: 12))
let str = "\(calculatedCoffee)<g>g</g>".style(tags: g)
.styleAll(all)
.attributedString
label.attributedText = str
You can find it here https://github.com/psharanda/Atributika
let attrString = NSAttributedString (
string: "title-title-title",
attributes: [NSAttributedStringKey.foregroundColor: UIColor.black])
Swifter Swift has a pretty sweet way to do this without any work really. Just provide the pattern that should be matched and what attributes to apply to it. They're great for a lot of things check them out.
``` Swift
let defaultGenreText = NSAttributedString(string: "Select Genre - Required")
let redGenreText = defaultGenreText.applying(attributes: [NSAttributedString.Key.foregroundColor : UIColor.red], toRangesMatching: "Required")
``
If you have multiple places where this would be applied and you only want it to happen for specific instances then this method wouldn't work.
You can do this in one step, just easier to read when separated.
Swift 4.x
let attr = [NSForegroundColorAttributeName:self.configuration.settingsColor, NSFontAttributeName: self.configuration.settingsFont]
let title = NSAttributedString(string: self.configuration.settingsTitle,
attributes: attr)
Swift 3.0
// create attributed string
Define attributes like
let attributes = [NSAttributedStringKey.font : UIFont.init(name: "Avenir-Medium", size: 13.0)]
Please consider using Prestyler
import Prestyler
...
Prestyle.defineRule("$", UIColor.red)
label.attributedText = "\(calculatedCoffee) $g$".prestyled()
Objective-C 2.0 example:
myUILabel.text = #"€ 60,00";
NSMutableAttributedString *amountText = [[NSMutableAttributedString alloc] initWithString:myUILabel.text];
//Add attributes you are looking for
NSDictionary *dictionaryOfAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont systemFontOfSize:12],NSFontAttributeName,
[UIColor grayColor],NSForegroundColorAttributeName,
nil];
//Will gray color and resize the € symbol
[amountText setAttributes:dictionaryOfAttributes range:NSMakeRange(0, 1)];
myUILabel.attributedText = amountText;

Strike through NSAttributedString: "Type of expression is ambiguous without more context"

Can anybody tell me what's wrong ?
let myTitle = NSAttributedString(string: Xdevices[row].deviceName!,
attributes: [NSFontAttributeName:UIFont(name: "Georgia", size:
15.0)!,NSForegroundColorAttributeName:UIColor.orangeColor(),
NSStrikethroughStyleAttributeName: NSUnderlineStyle.StyleSingle])
The error is:
Type of expression is ambiguous without more context
This happened after inserting NSStrikethroughStyleAttributeName: NSUnderlineStyle.StyleSingle
Try this:
let attributes = [
NSFontAttributeName: UIFont(name: "Georgia", size: 15.0)!,
NSForegroundColorAttributeName: UIColor.orangeColor(),
NSStrikethroughStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue)
]
let myTitle = NSAttributedString(string: Xdevices[row].deviceName!, attributes: attributes)
NSAttributedString(string:attributes:) expects a dictionary of type [String: AnyObject]. Howeverm StyleSingle is an Int. Hence you must wrap it inside an NSNumber.