How to create random string with multiple formats? - swift

I need to create a random string with format which can convert any string(including parenthesis() to another color on swift: for example:
Hey (Hey) : First part 'Hey' is fine, but I want to change : (Hey) to a different color
same goes if I choose another string
Hi (What's Up) ....
And tried the following
let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 50)))
let color = UIColor(white: 0.2, alpha: 1)
let attributedTextCustom = NSMutableAttributedString(string: "(\(String())", attributes: [.font: UIFont(name:"AvenirNext-Medium", size: 16)!, .foregroundColor: color]))
attributedTextCustom.append(NSAttributedString(string: " (\(String())", attributes: [.font: UIFont(name: "AvenirNext-Regular", size: 12)!, .foregroundColor: UIColor.lightGray]))
label.attributedText = attributedTextCustom
Something like this is the behavior I am looking for (just for demostration...):

You can use a regex "\\((.*?)\\)" to find the range of the word between the parentheses and add the color attribute to a NSMutableAttributedString:
let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 50)))
let sentence = "Hello (Playground)"
let mutableAttr = NSMutableAttributedString(string: sentence, attributes: [.font: UIFont(name:"AvenirNext-Medium", size: 16)!, .foregroundColor: UIColor.black])
if let range = sentence.range(of: "\\((.*?)\\)", options: .regularExpression) {
let color = UIColor(white: 0.2, alpha: 1)
let attributes: [NSAttributedString.Key: Any] = [.font: UIFont(name:"AvenirNext-Medium", size: 16)!, .foregroundColor: color]
mutableAttr.addAttributes(attributes, range: NSRange(range, in: sentence))
label.attributedText = mutableAttr
}

Related

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)

MacOS: Add a text overlay to an image in Swift

I've written a small extension for UIImage, which adds a text to an image:
extension UIImage {
func addTextToImage(textToAdd: String) -> UIImage {
let textColor = UIColor.white
let textFont = UIFont(name: "Snell Roundhand", size: 40)!
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(self.size, false, scale)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = NSTextAlignment.center
var textFontAttributes = [
NSAttributedString.Key.font: textFont,
NSAttributedString.Key.foregroundColor: textColor,
NSAttributedString.Key.paragraphStyle: paragraphStyle
] as [NSAttributedString.Key : Any]
self.draw(in: CGRect(origin: CGPoint.zero, size: self.size))
let textFrame = CGPoint(x: self.size.width/4, y: self.size.height/4)
let rect = CGRect(origin: textFrame, size: CGSize(width: self.size.width/2, height: self.size.height/2) )
text.draw(in: rect, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
The result should look like this:
Now I want to do the same thing for NSImage to run on MacOS.
Any ideas how to do this?
All similar questions on Stackoverflow are either very old, unanswered or in Objective C
Found a solution:
extension NSImage {
func addTextToImage(drawText text: String) -> NSImage {
let targetImage = NSImage(size: self.size, flipped: false) { (dstRect: CGRect) -> Bool in
self.draw(in: dstRect)
let textColor = NSColor.white
let textFont = NSFont(name: "Snell Roundhand", size: 36)! //Helvetica Bold
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = NSTextAlignment.center
var textFontAttributes = [
NSAttributedString.Key.font: textFont,
NSAttributedString.Key.foregroundColor: textColor,
] as [NSAttributedString.Key : Any]
let textOrigin = CGPoint(x: self.size.height/3, y: -self.size.width/4)
let rect = CGRect(origin: textOrigin, size: self.size)
text.draw(in: rect, withAttributes: textFontAttributes)
return true
}
return targetImage
}
}

Clipped text on UILabel

I'm using custom a font for UILabel but there is a strange problem, for some characters the text is being clipped:
The label should be like this (label frame has enlarged manually):
This is the code to add the label to the gray view:
let string = "کیخسروی"
let font = UIFont(name: "IranNastaliq", size: 30)!
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byWordWrapping
paragraphStyle.alignment = .center
let attributes: [NSAttributedStringKey: Any] = [
.font: font,
.paragraphStyle: paragraphStyle
]
let mutabbleAttributedString = NSMutableAttributedString(string: string, attributes: attributes)
let rectSize = mutabbleAttributedString.size()
let label = UILabel(frame: CGRect(x: 0, y: 0, width: rectSize.width, height: rectSize.height))
label.font = font
label.attributedText = mutabbleAttributedString
label.backgroundColor = UIColor.yellow
label.textAlignment = .center
let size = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
let width = label.sizeThatFits(size).width
let height = label.sizeThatFits(size).height
let frame = CGRect(x: 0, y: 0, width: width, height: height)
label.frame = frame
self.myView.addSubview(label)
label.center = self.myView.center
Seems sizeThatFits() does not calculate the bounds correctly.
I have to mention this clipping only happens while using some custom fonts.

UITextView frame doesn't care about the attributes of its content

I have a UITextView with an attributedText (containing font & lineSpacing to put lines closer).
I use the code below to determine the frame of the textView.
The problem is the frame.height is too much big, and doesn't seem to care about lineSpacing. It looks like the frame of the textView without specific lineSpacing.
Does anyone have an idea to fix this fail? Did I miss something?
//Attributes of textView
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = -1.25
let textViewText = Data().text
let attributedText = NSMutableAttributedString(string: textViewText, attributes: [NSFontAttributeName: UIFont(name: "AvenirNext-Medium", size: 14)!])
attributedText.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: attributedText.string.characters.count))
textView.attributedText = attributedText
...
//Determining the frame of textView in other method
let textViewText = Data().text
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = -1.25
let rect = NSString(string: textViewText).boundingRect(with: CGSize(width: view.bounds.size.width, height: view.bounds.size.height),
options: NSStringDrawingOptions.usesFontLeading.union(NSStringDrawingOptions.usesLineFragmentOrigin),
attributes: [NSFontAttributeName: UIFont(name: "AvenirNext-Medium", size: 14)!, NSParagraphStyleAttributeName: paragraphStyle],
context: nil)

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.