Rendering text in italics using core text in iOS - ios

I want to render text in italics using core text. In UILabel, I was able to apply italics style(basically slanting the text) for a regular font by adding obliqueness attribute to the NSMutableAttributedString. Please refer the code and output below,
let attributes: [NSAttributedString.Key: Any] =
.font: UIFont(name: "YesevaOne-Regular", size: 20),
.obliqueness: 0.3
]
let label = "FontTest"
let attributedString = NSMutableAttributedString(string: label)
attributedString.addAttributes(attributes, range: NSRange.init(location: 0, length: (label as NSString).length))
fontestLabel.attributedText = attributedString
But, when i do the same in core text, the obliqueness attribute not getting applied to the text, whereas the other attributes like strokewidth, strokecolor was getting applied. I have added the code which i used and output below,
let attrString = NSMutableAttributedString(string: "Font Test")
let attributes: [NSAttributedString.Key: Any] = [
.backgroundColor : UIColor.white.cgColor,
.font : UIFont(name: "YesevaOne-Regular", size: 20)!,
.strokeWidth: -5,
.obliqueness: 0.3,
]
attrString.addAttributes(attributes, range: NSRange(location: 0, length: attrString.length))
let framesetter = CTFramesetterCreateWithAttributedString(attrString as CFAttributedString)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attrString.length), path, nil)
CTFrameDraw(frame, context)
Please help me, if anyone come across this situation?
PS: The custom font, which i used doesn't have italics ttf.

Related

NSAttributedString: how to make multiline in another NSAttributedString

I am trying to create a multiline separate text in another text to achieve the below text style.
I have tried the below code to produce the goal but the third part of the code is creating a issue (with medium font)
private func createLimitedDetailText() -> NSAttributedString {
let totalText = "Attension, only\n 6 spaces\n left!"
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let attributedString = NSMutableAttributedString(string: totalText, attributes: [
.font: FontFamily.OpenSans.light.font(size: 29.0),
.foregroundColor: UIColor.white,
])
let bigText = attributedString.addAttribute(.font, value: FontFamily.OpenSans.extrabold.font(size: 70), range: NSRange(location: 17, length: 1))
let medium = attributedString.addAttribute(.font, value: FontFamily.OpenSans.semibold.font(size: 29), range: NSRange(location: 18, length: 14))
let textRange = NSRange(location: 0, length: attributedString.length)
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: textRange)
return attributedString
}
In case anyone is wondering the answer, below code generates the exact same result:
private func createLimitedDetailText() -> NSAttributedString {
let totalText = "Attension, only\n 6"
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineHeightMultiple = 0.90
paragraphStyle.alignment = .center
let attributedString = NSMutableAttributedString(string: totalText, attributes: [
.font: FontFamily.OpenSans.light.font(size: 29.0),
.foregroundColor: UIColor.white,
NSAttributedString.Key.paragraphStyle: paragraphStyle
])
attributedString.addAttribute(.font, value: FontFamily.OpenSans.extrabold.font(size: 70), range: NSRange(location: 17, length: 1))
let paragraphStyle2 = NSMutableParagraphStyle()
paragraphStyle2.lineHeightMultiple = 0.30
paragraphStyle2.alignment = .center
let attributedString2 = NSMutableAttributedString(string: " spaces\n left!", attributes: [
.font: FontFamily.OpenSans.semibold.font(size: 29.0),
.foregroundColor: UIColor.white,
.baselineOffset: 35,
.paragraphStyle: paragraphStyle2
])
attributedString.append(attributedString2)
return attributedString
}

Wrong height for UILabel when using custom lineSpacing and kern

I am getting wrong height for an UILabel if I use NSAttributedString that has custom kern and lineSpacing.
Here is how I set the custom kern and line spacing:
override func viewDidLoad() {
super.viewDidLoad()
let shortText = "Single line"
self.label.attributedText = self.getAttributedText(text: shortText, kern: 0.2, lineSpacing: 8)
self.label2.attributedText = self.getAttributedText(text: shortText, kern: 0, lineSpacing: 8)
}
private func getAttributedText(text: String, kern: CGFloat, lineSpacing: CGFloat) -> NSAttributedString {
let attributedString = NSMutableAttributedString(string: text)
let style = NSMutableParagraphStyle()
style.lineSpacing = lineSpacing
let attributes: [NSAttributedStringKey : Any] =
[.paragraphStyle : style,
.kern: kern]
attributedString.addAttributes(attributes,
range: NSMakeRange(0, attributedString.length))
return attributedString
}
And here is what I get:
The first label (the one that has custom kern), has its height wrong. It's exactly 8 points taller than it should be - that's the custom line height that I am using.
This only happens for single line labels. If I use text that is on a couple of lines, it works as expected.
This is a bug with NSAttributedStringKey.kern. As a workaround, you can calculate the number of lines of your UILabel with the suggestions in this answer. If it has one line only, set lineSpacing to 0.
private func getAttributedText(text: String, kern: CGFloat, lineSpacing: CGFloat) -> NSAttributedString {
let attributedString = NSMutableAttributedString(string: text)
let font = UIFont.systemFont(ofSize: 16)
let attributes: [NSAttributedStringKey : Any] = [.kern: kern,
.font: font]
attributedString.addAttributes(attributes, range: NSMakeRange(0, attributedString.length))
let maxSize = CGSize(width: [custom width], height: CGFloat.greatestFiniteMagnitude)
let sizeOfLabel = attributedString.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, context: nil)
if sizeOfLabel.height > font.lineHeight {
let style = NSMutableParagraphStyle()
style.lineSpacing = lineSpacing
attributedString.addAttribute(.paragraphStyle, value: style, range: NSMakeRange(0, attributedString.length))
}
return attributedString
}

Adding font size and custom font name to attributed string in UITextView

I have the following code to add the attributed string to the UITextView text. I need to add the custom font and font size to it in swift. How to do it?
func setAttributedString(string: String) -> NSAttributedString {
let attrString = NSMutableAttributedString(string: string)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 7
paragraphStyle.minimumLineHeight = 7
attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSRange(location: 0, length:attrString.length))
attrString.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 30), range: NSRange(location: 0, length:attrString.length))
return attrString
}
I need to add the custom font and font size to the following function. How to achieve this?
In Swift 3
let attributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 17)!,
NSAttributedStringKey.foregroundColor: UIColor.white]
let attributedString = NSMutableAttributedString(string: "Your string" , attributes: attributes)
Use the initializer init(string:attributes:)
https://developer.apple.com/documentation/foundation/nsattributedstring/1408136-init
let attrString = NSMutableAttributedString(string: string, attributes:
[NSFontAttributeName:UIFont(
name: "Georgia",
size: 18.0)!])
//Add more attributes here

ios swift: Is it possible to change the font style of a certain word in a string?

I am extracting from a DB contents as strings. With a method I extract the longest word out of this string.
Now I would like to print out the entire string to a text label but would like to highlight the longest word in a different color and text style within the string.
How can I do that?
Do I need to cut the string into pieces - set the formatting - and put them all together again before giving it to the label?
Or is there any other (better) way?
If you already know the longest word you have to get the range of that word in the string. I prefer the NSString method rangeOfString: for this.
You then create a NSMutableAttributedString from the string, with your default attributes. Finally you apply highlighting attributes to the range you figured out earlier.
let longString = "Lorem ipsum dolor. VeryLongWord ipsum foobar"
let longestWord = "VeryLongWord"
let longestWordRange = (longString as NSString).rangeOfString(longestWord)
let attributedString = NSMutableAttributedString(string: longString, attributes: [NSFontAttributeName : UIFont.systemFontOfSize(20)])
attributedString.setAttributes([NSFontAttributeName : UIFont.boldSystemFontOfSize(20), NSForegroundColorAttributeName : UIColor.redColor()], range: longestWordRange)
label.attributedText = attributedString
Update for Swift 5.0
let longestWordRange = (longString as NSString).range(of: longestWord)
let attributedString = NSMutableAttributedString(string: longString, attributes: [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 20)])
attributedString.setAttributes([NSAttributedStringKey.font : UIFont.boldSystemFont(ofSize: 20), NSAttributedStringKey.foregroundColor : UIColor.red], range: longestWordRange)
Which looks like this in my playground:
You want to look at Attributed Strings and NSRange. You can use both of these together to create different styles for ranges in the string. Here is a snippet:
myMutableString = NSMutableAttributedString(string: myString, attributes: [NSFontAttributeName:UIFont(name: "Georgia", size: 18.0)!])
//Add more attributes here:
myMutableString.addAttribute(NSFontAttributeName, value: UIFont(name: "Chalkduster", size: 24.0), range: NSRange(location: 7,length: 5))
myMutableString.addAttribute(NSFontAttributeName, value: UIFont(name: "AmericanTypewriter-Bold", size: 18.0)!, range: NSRange(location:2,length:4))
myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSRange(location:2,length:4))
myMutableString.addAttribute(NSFontAttributeName, value: UIFont(name: "Georgia", size: 36.0)!, range: NSRange(location: 0, length: 1))
myMutableString.addAttribute(NSStrokeColorAttributeName, value: UIColor.blueColor(), range: NSRange(location: 0, length: 1))
myMutableString.addAttribute(NSStrokeWidthAttributeName, value: 2, range: NSRange(location: 0, length: 1))
myMutableString.addAttribute(NSBackgroundColorAttributeName, value: UIColor.greenColor(), range: NSRange(location: 0, length: myString.length))
myLabel.backgroundColor = UIColor.grayColor()
//Apply to the label
myLabel.attributedText = myMutableString
NSMutableAttributedString.
You create an NSMutableAttributedString and apply the effects you'd like with addAttributes:range.
Then assign it to the attributedText property of your UILabel.

NSTextAttachment image alignment

I am following this cool tutorial Implementing Rich Text with Images on OS X and iOS by #Duncan Groenewald and was able to display images in my UITextView. However, these images are not centered they way I would like them to be. See image
As you can see, I would like my image to be centered on the X-axis.
I tried returning the rect with appropriate values in -attachmentBoundsForTextContainer:proposedLineFragment:glyphPosition:characterIndex but that did not help.
I also tried setting the NSKernAttributeName for the NSTextAttachment attributed string. But all it did was hide the image some how.
Try setting the paragraph style on your attachment with a center alignment.
If your images are embedded in an attributed string as attachments, you can access them by enumerating through the attributed string's attachment attributes.
For example:
attributedContent.enumerateAttribute(NSAttachmentAttributeName, inRange: NSRange(location: 0, length: attributedContent.length), options: nil) { (attribute, range, stop) -> Void in
if let attachment = attribute as? NSTextAttachment {
// this example assumes you want to center all attachments. You can provide additional logic here. For example, check for attachment.image.
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .Center
attributedContent.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: range)
}
}
This is Swift 3.1 using extension:
extension NSMutableAttributedString {
func setAttachmentsAlignment(_ alignment: NSTextAlignment) {
self.enumerateAttribute(NSAttachmentAttributeName, in: NSRange(location: 0, length: self.length), options: .longestEffectiveRangeNotRequired) { (attribute, range, stop) -> Void in
if attribute is NSTextAttachment {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = alignment
self.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: range)
}
}
}
}
In this way you can you easily apply alignment for attachments on attributed string:
let attributeString = NSMutableAttributedString(string: "")
// add attachments
attributeString.setAttachmentsAlignment(.center)
Here's another way how to set the alignment for an NSTextAttachment image. Hopefully this will also help someone struggling with this. I'm using the code below in a func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
var buttonText = "My Button";
let align = NSMutableParagraphStyle();
align.alignment = NSTextAlignment.center;
align.firstLineHeadIndent = 10.0;
align.headIndent = 10.0;
align.tailIndent = -10.0;
let para = NSMutableAttributedString();
// top padding
para.append(NSAttributedString(string: "\n", attributes: [NSParagraphStyleAttributeName: align, NSFontAttributeName: UIFont(name: "Helvetica", size: 10.0)!, NSForegroundColorAttributeName: UIColor.white]));
// image
let img = NSTextAttachment();
img.image = UIImage(named: "MyIcon");
img.bounds = CGRect(x: 0, y: UIFont(name: "Helvetica", size: 18.0)!.descender, width: img.image!.size.width, height: img.image!.size.height);
let nas = NSAttributedString(attachment: img).mutableCopy() as! NSMutableAttributedString;
nas.addAttribute(NSParagraphStyleAttributeName, value: align, range: NSRange(location: 0, length: nas.length));
para.append(nas);
// space to text
buttonText = " " + buttonText;
// text
para.append(NSAttributedString(
string: buttonText,
attributes: [NSParagraphStyleAttributeName: align, NSFontAttributeName: UIFont(name: "Helvetica", size: 18.0)!, NSForegroundColorAttributeName: UIColor.black]));
// bottom padding
para.append(NSAttributedString(string: "\n", attributes: [NSParagraphStyleAttributeName: align, NSFontAttributeName: UIFont(name: "Helvetica", size: 10.0)!, NSForegroundColorAttributeName: UIColor.white]));
// set cell label
let label = cell.textLabel!;
label.numberOfLines = 0;
label.layer.borderWidth = 0;
label.layer.masksToBounds = false;
label.backgroundColor = UIColor.clear;
label.layer.backgroundColor = UIColor.green;
label.attributedText = para;

Resources