Over the past few months I have received questions about NSAttributedString+HTML and Rich Text Editing. Here are the Frequently Asked Questions.
I generally abbreviate NSAttributedString+HTML as NSAS+HTML. If your question or app is not in this list please let me know.
General / Cost / Licensing
What is NSAS+HTML?
Cocoa on the Mac has an initWithHTML method on NSAttributedString. NSAS+HTML consists of 3 parts:
- A reverse-engineered and enhanced implementation of the Mac initWithHTML for use on iOS
- UI classes to properly render the created NSAttributedString
- Objective-C wrapper classes for CoreText to simplify it’s use
The goal of NSAS+HTML is to provide a comprehensive way to eliminate UIWebViews from your apps and reap the benefits of being able to fully control the way the rich text is rendered and how your users interact with it.
Where does it live? How do you contribute to it?
NSAS+HTML is hosted on GitHub. If you find problems then please open an issue there. If you fix a problem or add a new feature then you can send a pull request so that the modifications from your fork can be merged into the master repository.
Does NSAS+HTML contain private APIs?
No. All code was newly created by the original author Oliver Drobnik as well as several contributors. NSAS+HTML is not a web browser, but instead renders views described with HTML.
Is NSAS+HTML legal to be used in App Store Apps?
Yes. A growing number of apps is using NSAS+HTML, the examples I know about are:
Please let me know if your app is not in this list so that I can add it.
How is NSAS+HTML licensed?
NSAttributedString+HTML is licensed under a BSD license. This means that you can use it for free in free and commercial products as long as you mention in the app that it contains “NSAttributedString+HTML copyright by Oliver Drobnik / Cocoanetics”.
Binary apps must display such a copyright notice somewhere accessible to the user, for example in the settings or about page. Source code apps must contain the license text file that is part of the GitHub project.
Is there a way to use NSAS+HTML without attributing it?
Yes. You can purchase a non-attribution license for €75 for it that eliminates the need for the attribution while still being able to use it in your commercial and free apps.
Does NSAS+HTML support Rich Text Editing?
No. By itself NSAS+HTML only renders. A commercial component of mine, called DTRichTextEditor, builds on it and adds text input.
What is the difference between DTAttributedTextView and DTAttributedTextContentView?
DTAttributedTextView is a scrollview sub class that has a DTAttributedTextContentView as sole sub view. DTAttributedTextContentView sizes itself to automatically fit the text.
What is the default font?
Times New Roman, 12 px. If you don’t specify any font attributes in the HTML this will be the font that is used. Headers are sized relative to that.
How do you change the default font size on DTAttributedTextView?
You can pass a dictionary with a variety of parameters to initWithHTML. One of these parameters is NSTextSizeMultiplierDocumentOption the text scale that causes all fonts to be a multiple of what their default would be. This affects all headers and body text equally.
Why does the first time attributed text is shown take 1 sec?
This is a bug in iOS that causes an extensive font matching table to be created the first time a CTFont is required. You have two possible workarounds available:
- Pre-initialize CoreText as shown here on a background thread.
- Put all the fonts you require in CoreTextFontOverrides.plist
If you only using one font then number 2 is the recommended method since it bypasses CoreText font matching.
What is the difference between Font, Font Face, Font Family and Font Variant?
A font family is the overall grouping of multiple fonts. Each font represents one look, like plain or bold. Font and Font Face are the same. Font is often used incorrectly synonymous with Font Family.
For example the Helvetica font family consists of these fonts/faces:
When NSAS+HTML requires a font face from a given family with a given size it will first look into the overrides plist (if present) and then use CoreText font matching.
Font Variants are different representations contained within the same font file/face. For example on iPad there is one font that contains also a small caps variant. A bold font is NOT a variant, it is a font in its own right.
How can DTAttributedTextView be used in table view cells?
DTAttributedTextView should not be used in table view cells because it is a scrollview. You can either use DTAttributedTextContentView and use their automatically sized heights for the heightForRowAtIndexPath or use the specially created DTAttributedTextCell class for that purpose. Please refer to DemoSnippetsViewController.m to see how it is used.
Please note that if you are using a different height for each row this dramatically reduces table view scrolling performance. Instead we recommend to use a fixed height.
After implementing DTAttributedTextView URLs show up but cannot be clicked, why?
NSAS+HTML is only in charge of rendering the text, you have to take care of the interactivity because everybody might have different needs.
NSAS+HTML provides delegate methods asking for custom subviews to be put over links. You can use the DTLinkButton provided with NSAS+HTML and have this perform any action you like.
What is DTTextAttachment?
DTTextAttachment encapsulates any kind of object that the layout process should reserve space for. This could be an image or a video. The space that is reserved for displaying this is taken from the displaySize property.
How are images rendered?
NSAS+HTML has two built in methods to render images. Either you enable the shouldDrawImages property on the content view which will draw local images together with the text. Or you implement the delegate method to provide your own UIView to show the contents of the DTTextAttachment that encapsulates the image.
For local images the contents property of the attachment contains the UIImage, for remote images the contentURL provides the URL for lazy loading. NSAS+HTML provides DTLazyImageView which demonstrates how to lazily load images from remote URLs, please refer to DemoTextViewController.m to see how this is integrated.
Note that you have to trigger a re-layout once you have loaded a remote image as soon as the actually displaySize of the DTTextAttachment is known. This step is not necessary if you specify a width/height in the HTML tag because then the displaySize of the attachment is known for layouting.
Does NSAS+HTML support Floating of Images?
No. Floating allows images to be positioned on the left or right side of the document and have text flow around them. Currently layouting is done in a single pass with one layout frame. To support floating of text attachments multiple passes would be required to determine the optimal sizing of multiple rectangles to be filled with text.
Does NSAS+HTML support multiple column layout?
Yes and No. The provided UI classes only work with a single layout frame.
To get multiple column layout you have to create your own UIView that takes multiple layout frames. The steps are:
- Create your DTCoreTextLayouter from the attributed string.
- Create a DTCoreTextLayoutFrame for the first column specifying the rectangle
- Create a second layout frame for the second column specifying another rectangle and the starting index that is one higher than the ending index in the first column
- Repeat this for each column
Once you have all these layout frames your UIView subclass only needs to call renderInContext for all columns.
Does NSAS+HTML support CSS styles sheets?
Not yet, but some contributors are working on this. At present only styles that are contained in the individual tags are recognized.
Does NSAS+HTML also allow for creating HTML out of attributed strings?
Yes. There is a htmlString method in the HTML category. This needs much work still.
Does NSAS+HTML support Margin or Padding?
No. Those are attributes that require the distribute the text into multiple blocks. There is no block level support in NSAS, essentially one layout frame is one big block.
You can specify edgeInsets on all sides for DTAttributedTextContentView which considers this inset on sizing the layout frame.