Thursday, August 2, 2018
Functional Formatting in Swift NSAttributedStrings and NSParagraphStyle
Functional Formatting in Swift NSAttributedStrings and NSParagraphStyle
Last year I wrote a post that concerned the use of NSAttributedStrings in Swift. In this post I take that code and rewrite it using a functional approach.
The first thing to do is to define functions that return functions.
typealias CharacterStyle = String -> NSAttributedStringWith these in place, the functions that will return these functions are written:
typealias ParagraphStyle = [NSAttributedString] -> NSAttributedString
Im not going to discuss at length here the process of what is explained in Functional Programming in Swift (Chapter 3: Wrapping Core Image). Instead, these are examples of how the principles could be applied to refine code that Ive written previously.
func bodyText(size:CGFloat, style:UIFontDescriptorSymbolicTraits?) -> CharacterStyle {
var desc = UIFontDescriptor(fontAttributes: [UIFontDescriptorTextStyleAttribute:UIFontTextStyleBody])
if let style = style {
desc = desc.fontDescriptorWithSymbolicTraits(style)
}
let font = UIFont(descriptor: desc, size: size)
return {
string in
return NSMutableAttributedString(string: string, attributes:[NSFontAttributeName:font])
}
}
func paragraph(indent indent:CGFloat, spacing:CGFloat) -> ParagraphStyle {
return { attrStrings in
let para = NSMutableAttributedString()
for s in attrStrings {
para.appendAttributedString(s)
}
let paraStyle = NSMutableParagraphStyle()
paraStyle.firstLineHeadIndent = indent
paraStyle.paragraphSpacingBefore = spacing
para.addAttribute(NSParagraphStyleAttributeName, value: paraStyle, range: NSRange(location: 0,length: para.string.characters.count))
return para
}
}
Note: The book tackles image filters and I transfer this knowledge to attributed strings.
Usage
Now the "boilerplate" code has been hidden away, the implementation can take place very simply and yet be flexible:// styling functions are createdOnce character styles have been applied to an array of strings, a paragraph can be constructed from the resulting array of attributed strings. One of the most appealing things about this approach is that it is possible to see immediately the styles being applied to each part of the paragraph.
let bodyStyle = bodyText(12, style: nil)
let bodyStyleItalic = bodyText(12, style: .TraitItalic)
// build an array of styled attributed strings
let attrStrings = [bodyStyle("Hello Swift! This is a tutorial looking at "),
bodyStyleItalic("attributed"), bodyStyle(" strings!")]
// create a paragraph from the strings
let para = paragraph(indent:10.0, spacing: 12.0)(attrStrings)
Notes
Notice the final line of code though, here a function that takes a function is returnedlet para = paragraph(indent:10.0, spacing: 12.0)and immediately employed by passing the argument (attrStrings). If wed wanted to separate things out then we couldve written:
let para = paragraph(indent:10.0, spacing: 12.0)But there is no need to.
para(attrStrings)
Finishing up
Finally some code to load this into a view// Create UITextViewand a gist containing the full code.
let view = UITextView(frame: CGRect(x: 0, y: 20, width: CGRectGetWidth(self.view.frame), height: CGRectGetWidth(self.view.frame)-20))
// Add string to UITextView
view.attributedText = para
// Add UITextView to main view
self.view.addSubview(view)
Follow @sketchytech
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.