Why are NSAttributedString's attributes influencing other AttributedStrings? - swift

In this case I'm setting a UILabel's attributedText with a combined NSAttributedString with different attributes for each line, and for some reason some AttributedString attributes influence the other AttributedStrings, but I thought their attributed are bound to the range of that particular AttributedString. I'm basically expecting that the NSAttributedString automatically gets its range set up when I append it to the NSMutableAttributedString.
Am I wrong?
In this case the shadows applies to the other appended AttributedStrings, in another case it is the bold font that overrides all fonts to come in the next AttributedStrings. Strange.
Here is some sample code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
textLabel.numberOfLines = 0
textLabel.lineBreakMode = .byWordWrapping
let myShadow = NSShadow()
myShadow.shadowBlurRadius = 3
myShadow.shadowOffset = CGSize(width: 3, height: 3)
myShadow.shadowColor = UIColor.gray
let attributedText = NSMutableAttributedString(string: "")
let fatString = NSMutableAttributedString(string: "Bold", attributes: [NSAttributedString.Key.foregroundColor : UIColor.green,
NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16),
NSAttributedString.Key.backgroundColor : UIColor.lightGray,
NSAttributedString.Key.shadow : myShadow])
let normalString = NSAttributedString(string: "\n\nNormal", attributes: [NSAttributedString.Key.foregroundColor : UIColor.white,
NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)])
let italicString = NSAttributedString(string: "\n\nItalic", attributes: [NSAttributedString.Key.foregroundColor : UIColor.yellow,
NSAttributedString.Key.font : UIFont.italicSystemFont(ofSize: 16)])
let otherFontString = NSAttributedString(string: "\n\nBold + Italic", attributes: [NSAttributedString.Key.foregroundColor : UIColor.gray,
NSAttributedString.Key.font : UIFont(descriptor: UIFontDescriptor().withSymbolicTraits([.traitBold, .traitItalic])!, size: 16)])
let normalString2 = NSAttributedString(string: "\n\nUnderlined", attributes: [NSAttributedString.Key.underlineStyle : NSUnderlineStyle.single.rawValue,
NSAttributedString.Key.foregroundColor : UIColor.red,
NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)])
attributedText.append(fatString)
attributedText.append(normalString)
attributedText.append(italicString)
attributedText.append(otherFontString)
attributedText.append(normalString2)
textLabel.attributedText = attributedText
}
}

Related

How to add strings with different fonts in UItextField?

I'm trying to add two part of text with different font parameters.
But they always get value from first string.
And there one strange thing, font color is set independently.
let descriptionTextView: UITextView = {
let view = UITextView()
let attributedText = NSMutableAttributedString(string: "Text", attributes:
[.font:UIFont.boldSystemFont(ofSize: 20),
.foregroundColor: UIColor.blue])
attributedText.append(NSAttributedString(string: "\n\n\n Other text", attributes:
[.font: UIFont.italicSystemFont(ofSize: 5),
.foregroundColor: UIColor.gray]))
view.attributedText = attributedText
view.translatesAutoresizingMaskIntoConstraints = false
view.textAlignment = .center
view.font = UIFont.boldSystemFont(ofSize: 20)
view.isEditable = false
view.isScrollEnabled = false
return view
}()
This is how it look in simulator
Remove
view.font = UIFont.boldSystemFont(ofSize: 20)

Nested NSAttributedString (s)

I am producing a PDF Invoice from my Swift app. Because not all address patched will be the same depth I am using carriage returns to layout the text. Address, Date, Invoice Number, Subject line and narrative, for example. it all works really well, however, I want to format the Subject line in bold text. I have looked all around this subject and drawn a blank. In essence my question is can you nest NSAttributed Strings, so that I can format the subjectline in Bold without having to create another NSAttributed String which would mean loosing my layout discipline?
This is my code
let textFont = UIFont.systemFont(ofSize: 10.0, weight: .regular)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .natural
paragraphStyle.lineBreakMode = .byWordWrapping
let textAttributes = [NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: textFont,
NSAttributedString.Key.kern : -0.15] as [NSAttributedString.Key : Any]
let attributedText = NSAttributedString(string: "\(billAddress)\r\r\r\("Invoice number: \ .
(invoiceNumber)")\r\("Date: \(mydate)")\r\r\r\("To")\r\r\(subjectline)\r\r\(narrative)",
attributes:
textAttributes as [NSAttributedString.Key : Any])
Any help/ideas/solution would be welcome
You can use NSMutableAttributedString, and append different parts of string using .append(_:) method. (https://developer.apple.com/documentation/foundation/nsmutableattributedstring/1417879-append)
Also you can take a look at https://github.com/Rightpoint/BonMot
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .natural
paragraphStyle.lineBreakMode = .byWordWrapping
let defaultAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 10.0, weight: .regular),
NSAttributedString.Key.kern : -0.15]
let boldAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 10.0, weight: .bold),
NSAttributedString.Key.kern : -0.15]
let attributedText = NSMutableAttributedString()
attributedText.append(NSAttributedString(string: (billAddress), attributes: defaultAttributes))
attributedText.append(NSAttributedString(string: "\r\r"))
attributedText.append(NSAttributedString(string: "Invoice number: \(invoiceNumber)", attributes: defaultAttributes))
attributedText.append(NSAttributedString(string: "\r"))
attributedText.append(NSAttributedString(string: "Date: \(mydate)", attributes: defaultAttributes))
attributedText.append(NSAttributedString(string: "\r\r"))
attributedText.append(NSAttributedString(string: "To", attributes: defaultAttributes))
attributedText.append(NSAttributedString(string: "\r\r"))
attributedText.append(NSAttributedString(string: subjectline, attributes: boldAttributes))
attributedText.append(NSAttributedString(string: "\r"))
attributedText.append(NSAttributedString(string: narrative, attributes: defaultAttributes))
let textRect = CGRect(x: 40, y: textTop, width: pageRect.width - 240,
height: pageRect.height - textTop - pageRect.height / 2 )
attributedText.draw(in: textRect)

iOS change the color of links for uilabel when using NSAttributedString

I'm using a uilabel and adding a link to by using NSAttributedString
let attributedText = NSMutableAttributedString(string: "http://www.google.com")
attributedText.addAttributes([NSAttributedString.Key.link: "https://www.google.com"], range: NSRange(location: 0, length: 21))
attributedText.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.red], range: NSRange(location: 0, length: 21))
label.attributedText = attributedText
label.tintColor = UIColor.red
How can get the link to be another color other than the other default blue link color provided by the UIKit framework.
Note: I do not want to use UITextView or UIWebView
let attributedText = "http://www.google.com"
let multipleAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.foregroundColor: UIColor.red,
NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue ]
let attributeString = NSAttributedString(string: attributedText, attributes: multipleAttributes)
// set attributed text on a UILabel
label.attributedText = attributeString

Color only underline in Swift

How do i change the color of my underline in a label? I want only the underline to change color, and not the entire text.
I have used this code to get the underline:
let underlineAttribute = [NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue]
let underlineAttributedString = NSAttributedString(string: "\(nearSavings[indexPath.row]) ,-", attributes: underlineAttribute)
cell.detailTextLabel?.attributedText = underlineAttributedString
But i cant find the code, to set the underline color. Anyone who can help?
Swift 4 Solution
You must use NSAttributedString with an array of attributes as [NSAttributedStringKey : Any].
Sample code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Colored Underline Label
let labelString = "Underline Label"
let textColor: UIColor = .blue
let underLineColor: UIColor = .red
let underLineStyle = NSUnderlineStyle.styleSingle.rawValue
let labelAtributes:[NSAttributedStringKey : Any] = [
NSAttributedStringKey.foregroundColor: textColor,
NSAttributedStringKey.underlineStyle: underLineStyle,
NSAttributedStringKey.underlineColor: underLineColor
]
let underlineAttributedString = NSAttributedString(string: labelString,
attributes: labelAtributes)
myLabel.attributedText = underlineAttributedString
}
}
Another solution could be to add a single line border under the label, that acts as an underline.
Get reference to the label
#IBOutlet weak var myLabel: UILabel!
Add the border under the label
let labelSize = myLabel.frame.size
let border = CALayer()
let w = CGFloat(2.0)
border.borderColor = UIColor.yellow.cgColor // <--- Here the underline color
border.frame = CGRect(x: 0, y: labelSize.height - w, width: labelSize.width, height: labelSize.height)
border.borderWidth = w
myLabel.layer.addSublayer(border)
myLabel.layer.masksToBounds = true
Note: with this workaround you underline the whole label. If you need to partially undlerline the text this solution is not appropiate
Swift 5 Solution
class UnderlinedLabel: UILabel {
override var text: String? {
didSet {
guard let text = text else { return }
let textColor: UIColor = .black
let underLineColor: UIColor = .lightGray
let underLineStyle = NSUnderlineStyle.single.rawValue
let labelAtributes:[NSAttributedString.Key : Any] = [
NSAttributedString.Key.foregroundColor: textColor,
NSAttributedString.Key.underlineStyle: underLineStyle,
NSAttributedString.Key.underlineColor: underLineColor
]
self.attributedText = NSAttributedString(string: text, attributes: labelAtributes)
}
}
}
Usage:
Just give class UnderlinedLabel to your label in the storyboard
The NSAttributedStringKey.underlineColor attribute does what you want:
let underlineAttributes = [
NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue,
NSAttributedStringKey.underlineColor: UIColor.orange
] as [NSAttributedStringKey : Any]
let underlineAttributedString = NSAttributedString(string: "Test", attributes: underlineAttributes)
This will set the underline color to orange whereas the text color will remain black.

Add several attributes to a NSMutableAttributedString

I'm trying to add several attributes to a NSMutableAttributedString; i tried this:
let stringNumero: NSString = "\(squadra.cori.count)" //= two-digit number
var stringNumeroMutable = NSMutableAttributedString()
stringNumeroMutable = NSMutableAttributedString(string: stringNumero as! String, attributes: [NSFontAttributeName: UIFont(name: "Noteworthy-Light", size: 9)!,
NSForegroundColorAttributeName: UIColor(red: 110/255.0, green: 183/255.0, blue: 93/255.0, alpha: 1.0)])
cell.numeroCori.attributedText = stringNumeroMutable
now I'd like to add an other attributes and i'm going uso this code:
stringNumeroMutable.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(8), range: NSRange(location: 0, length: 1))
but I'm incurring in a problem:
as you see, the bold effect is attributed only to the first digit and the previous attributed (such as the font) disappear. I think the the second NSFontAttributedName subscribe the previous one, so is there any way to set both font and bold?
Thanks a lot!!!
Edit: as suggested i tried to recall the method like this:
let stringNumero: NSString = "\(squadra.cori.count)" //= two-digit number
var stringNumeroMutable = NSMutableAttributedString()
stringNumeroMutable = NSMutableAttributedString(string: stringNumero as! String, attributes: [NSFontAttributeName: UIFont(name: "Noteworthy-Light", size: 9)!,
NSForegroundColorAttributeName: UIColor(red: 110/255.0, green: 183/255.0, blue: 93/255.0, alpha: 1.0)])
cell.numeroCori.attributedText = stringNumeroMutable
stringNumeroMutable.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(9), range: NSRange(location: 0, length: stringNumeroMutable.length))
cell.numeroCori.atributedText = stringNumeroMutable
but the second call overwrite the first one (so the number loose the attributed font). How to solve this?
I think your problem, that you use method boldSystemFontOfSize
boldSystemFontOfSize:
Returns the font object used for standard interface items that are
rendered in boldface type in the specified size.
See my solution:
#IBOutlet weak var label: UILabel!
var mutableAttributedString: NSMutableAttributedString!
override func viewDidLoad() {
super.viewDidLoad()
let someString = "Hello World"
let attr: [String: AnyObject] = [NSFontAttributeName: UIFont(name: "Helvetica", size: 10)!,
NSForegroundColorAttributeName: UIColor(red: 0.18, green: 0.18, blue: 0.18, alpha: 1.0)]
mutableAttributedString = NSMutableAttributedString(string: someString, attributes: attr)
label.attributedText = mutableAttributedString
}
#IBAction func buttonPressed(sender: UIButton) {
let font = mutableAttributedString.attribute(NSFontAttributeName, atIndex: 1, effectiveRange: nil)!
mutableAttributedString.addAttribute(NSFontAttributeName, value: font.fontWithSize(20) , range: NSMakeRange(0, mutableAttributedString.length))
label.attributedText = mutableAttributedString
}
In buttonPressed function you define current font of mutableAttributedString and then you can change font's size with method fontWithSize.