Note: Code has been updated following changes to UIFont in Xcode (6.1).
Cut and paste this code into your viewDidLoad. Run in the iOS Simulator on an iPhone (to see full effect of paragraph styling). The comments explain what is happening.
// Define string attributes let font = UIFont(name: "Georgia", size: 18.0) ?? UIFont.systemFontOfSize(18.0) let textFont = [NSFontAttributeName:font] let fontItal = UIFont(name: "Georgia-Italic", size: 18.0) ?? UIFont.systemFontOfSize(18.0) let italFont = [NSFontAttributeName:fontItal] // Create a string that will be our paragraph let para = NSMutableAttributedString() // Create locally formatted strings let attrString1 = NSAttributedString(string: "Hello Swift! This is a tutorial looking at ", attributes:textFont) let attrString2 = NSAttributedString(string: "attributed", attributes:italFont) let attrString3 = NSAttributedString(string: " strings.", attributes:textFont) // Add locally formatted strings to paragraph para.appendAttributedString(attrString1) para.appendAttributedString(attrString2) para.appendAttributedString(attrString3) // Define paragraph styling let paraStyle = NSMutableParagraphStyle() paraStyle.firstLineHeadIndent = 15.0 paraStyle.paragraphSpacingBefore = 10.0 // Apply paragraph styles to paragraph para.addAttribute(NSParagraphStyleAttributeName, value: paraStyle, range: NSRange(location: 0,length: para.length)) // Create UITextView 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) // For a more detailed look at UITextView (not yet in Swift) see: http://sketchytech.blogspot.co.uk/2013/11/making-most-of-uitextview-in-ios-7.html?q=UITextview
UIFont Class
The reason for usinglet font = UIFont(name: "Georgia", size: 18.0) ?? UIFont.systemFontOfSize(18.0)is revealed if we look at the UIFont class as represented in the header file:
class UIFont : NSObject, NSCopying { // Returns an instance of the font associated with the text style and scaled appropriately for the user's selected content size category. See UIFontDescriptor.h for the complete list. @availability(iOS, introduced=7.0) class func preferredFontForTextStyle(style: String) -> UIFont // Returns a font using CSS name matching semantics. init?(name fontName: String, size fontSize: CGFloat) -> UIFont // Returns an array of font family names for all installed fonts class func familyNames() -> [AnyObject] // Returns an array of font names for the specified family name class func fontNamesForFamilyName(familyName: String) -> [AnyObject] // Some convenience methods to create system fonts class func systemFontOfSize(fontSize: CGFloat) -> UIFont class func boldSystemFontOfSize(fontSize: CGFloat) -> UIFont class func italicSystemFontOfSize(fontSize: CGFloat) -> UIFont // Font attributes var familyName: String { get } var fontName: String { get } var pointSize: CGFloat { get } var ascender: CGFloat { get } var descender: CGFloat { get } var capHeight: CGFloat { get } var xHeight: CGFloat { get } @availability(iOS, introduced=4.0) var lineHeight: CGFloat { get } var leading: CGFloat { get } // Create a new font that is identical to the current font except the specified size func fontWithSize(fontSize: CGFloat) -> UIFont // Returns a font matching the font descriptor. If fontSize is greater than 0.0, it has precedence over UIFontDescriptorSizeAttribute in fontDescriptor. init(descriptor: UIFontDescriptor, size pointSize: CGFloat) -> UIFont // Returns a font descriptor which describes the font. @availability(iOS, introduced=7.0) func fontDescriptor() -> UIFontDescriptor }we see in the following line that UIFont has an optional initialiser:
init?(name fontName: String, size fontSize: CGFloat) -> UIFontmeaning that it won't necessarily create an instance and might instead return nil. For example, if a font with the specified name does not exist. It is therefore possible to conceive of a situation where we might have a font that we'd most of all like but also have fallbacks:
let font = UIFont(name: "Garamond", size: 18.0) ?? UIFont(name: "Voyager", size: 18.0) ?? UIFont(name: "Georgia", size: 18.0) ?? UIFont.systemFontOfSize(20.0)The final option being a guaranteed font returned by a type (or class) method.
Checking against available fonts
The alternative to using the nil coalescing operator would be to check first whether a font exists:
contains(UIFont.familyNames() as [String],"Georgia")And we can imagine using
let fontName = "Georgia" let font = contains(UIFont.familyNames() as [String],fontName) ? UIFont(name: fontName, size: 18.0) : UIFont.systemFontOfSize(18.0)
but not only is it wordier than simply writing
So rather than feel a responsibility to search the family names, it would appear a better practice to take advantage of nil coalescing, and reserve use of the familyNames() type method for when a list of font names, for example, is presented to the user.
let font = UIFont(name: "Georgia", size: 18.0) ?? UIFont.systemFontOfSize(18.0)and possibly more memory intensive, but the code (which searches the family names) returns an optional. This either means we need to force unwrap
let font:UIFont! = contains(UIFont.familyNames() as [String],fontName) ? UIFont(name: fontName, size: 18.0) : UIFont.systemFontOfSize(18.0)or we need to test for nil before use, which potentially entangles us in a web of optionals and nil testing.
Conclusion
The nil coalescing operator approach, which at first might appear a rather slap dash way of doing things, becomes a way of slicing through the gordian knot of optionals that can materialise with fonts in particular, where it cannot be guaranteed that a system has the desired font.So rather than feel a responsibility to search the family names, it would appear a better practice to take advantage of nil coalescing, and reserve use of the familyNames() type method for when a list of font names, for example, is presented to the user.
Extras
It is possible to add any NSObject:AnyObject pair to the attributes dictionary of an NSAttributedString meaning that for example one could add id and class values and any other kind of value too. Only the recognized keys are taken into account when drawing the attributed strings:
let NSFontAttributeName: String let NSParagraphStyleAttributeName: String let NSForegroundColorAttributeName: String let NSBackgroundColorAttributeName: String let NSLigatureAttributeName: String let NSKernAttributeName: String let NSStrikethroughStyleAttributeName: String let NSUnderlineStyleAttributeName: String let NSStrokeColorAttributeName: String let NSStrokeWidthAttributeName: String let NSShadowAttributeName: String let NSTextEffectAttributeName: String let NSAttachmentAttributeName: String let NSLinkAttributeName: String let NSBaselineOffsetAttributeName: String let NSUnderlineColorAttributeName: String let NSStrikethroughColorAttributeName: String let NSObliquenessAttributeName: String let NSExpansionAttributeName: String let NSWritingDirectionAttributeName: String let NSVerticalGlyphFormAttributeName: StringBut all are stored, which could be convenient for retaining style information used in a document format when translating to and from attributed strings.
i need to change color of text in uitextview...
ReplyDeleteYou need to add the NSForegroundColorAttributeName key to your string attributes dictionary and give it a value of a UIColor. Let me know if you need sample code written out.
Delete