By Adobe
 
Created
26 July 2010
 

Requirements

 
Prerequisite knowledge

This article assumes you have prior experience working with Adobe Flash Professional. Some familiarity working with Adobe ActionScript 3 is recommended.

 
User level

Intermediate
 

 
Required products

 
Sample files

The Text Layout Framework (TLF) is a component library written entirely in Adobe ActionScript 3. The TLF library contains approximately 100 ActionScript 3 classes and interfaces organized into 10 packages, which provide a high level of programmatic control over text objects.
 
Unlike the Flash Text Engine, the Text Layout Framework is not built into Adobe Flash Player. It is an independent library written entirely in ActionScript 3. A published SWF file using TLF functionality requires Flash Player 10 (or later) to play.
 
In this article, you'll learn how to create TLF text objects and how the Text Layout Framework classes are structured. I'll provide the steps to format TLF text and display text objects on the Stage. I'll also cover how XML data can be incorporated and describe best practices for separating content functions from formatting functions to achieve advanced typographical effects.
 

 
Using a TextFlow object to structure text data

When you use the Text Layout Framework, text content is structured and stored in a TextFlow object. The text content is called a "story." You can format TLF content by referencing the TextFlow object in XHTML. To see how this is accomplished, I'll begin by structuring some simple text data: "Hello, World".
 
The TextFlow object is the root element and can contain ParagraphElement instances representing the paragraph elements of text. A ParagraphElement instance cannot directly store text or graphic content; these items are stored within the SpanElement, which has the SpanElement.text property. Therefore, a SpanElement instance (which contains text as its property) is added to a ParagraphElement instance.
 
The TextFlow instance is created using the following XHTML syntax:
 
<TextFlow><p><span>Hello, World</span></p></TextFlow>
I cover this concept in greater detail later in the section, Creating a TextFlow object from XML data of Text Layout Framework Markup. Table 1 lists the basic classes used to create structured elements of Text Layout Framework text content.
 
Table 1. Classes used for TLF structured elements
 
Class
 
Corresponding XHTML element
 
Classes that can be contained inside each class
 
root (html)
 
ParagraphElement / DivElement
 
p
 
SpanElement / InlineGraphicElement / LinkElement / TCYElement
 
span
 
none
 
Each element instance is generated by their constructor methods, following the basic rule of programming in ActionScript 3. The FlowGroupElement.addChild() method adds a child element to a parent element. While the method's name is the same as the DisplayObjectContainer.addChild() method, it does not display the element on the Stage.
 
The code example shown below creates a text object with a TextFlow instance containing the structured data of the text string: "Hello, World". The FlowGroupElement.getText() method displays the text in the Output panel of the Flash authoring environment:
 
// frame action import flashx.textLayout.elements.TextFlow; import flashx.textLayout.elements.ParagraphElement; import flashx.textLayout.elements.SpanElement; var myFlow:TextFlow = new TextFlow(); // <TextFlow></TextFlow> var paragraph:ParagraphElement = new ParagraphElement(); // <p></p> var span:SpanElement = new SpanElement(); // <span></span> span.text = "Hello, World"; // <span>Hello, World</span> paragraph.addChild(span); // <p><span>Hello, World</span></p> myFlow.addChild(paragraph); // <TextFlow><p><span>Hello, World</span></p></TextFlow> trace(myFlow.getText()); // Output: Hello, World
That's all it takes to output a TextFlow text string. In the next section, you'll go a step further and create a TLF display object (a TextLine object) from a TextFlow object using the TextFlowTextLineFactory class to display the TLF text in a published SWF file.
 

 
Creating a TextLine object from a TextFlow object to display TLF text content on the Stage

The TextFlow class does not inherit from the DisplayObject class. This means that you cannot pass a TextFlow object to the DisplayObjectContainer.addChild() method in order to display its text content on the Stage. To achieve this, you'll create a TextLine object, instead (which is a subclass of the DisplayObject). The classes that the TextFlow class inherits from are listed in the Flash Help documentation (see Figure 1).
 
The TextFlow diagram from "ActionScript 3.0 Reference for the Adobe Flash Platform" shows that the TextFlow class does not inherit from the DisplayObject class.
Figure 1. The TextFlow diagram from "ActionScript 3.0 Reference for the Adobe Flash Platform" shows that the TextFlow class does not inherit from the DisplayObject class.
You can use the TextFlowTextLineFactory.createTextLines() method to create the TextLine object. There are two important things to consider when using this method. First, the TextFlowTextLineFactory instance you are referencing must have a Rectangle object that specifies the area of text in the TextLineFactoryBase.compositionBounds property.
 
Second, when this method creates a TextLine object, it calls the callback function and passes the created TextLine instance to the function as an argument. Therefore, the callback function should be defined.
 
The TextFlowTextLineFactory.createTextLines() method is called with two arguments, a callback function and a TextFlow object, as shown below:
 
textFlowTextLineFactory.createTextLines(callback, textFlow); function callback(textLine):void { // processing the TextLine object }
The code example below (script 1) dynamically creates a simple story (containing the text, "Hello, World") with the Text Layout Framework and places it on the timeline. When you paste this code into a frame script and choose Control > Test Movie, the SWF file displays the "Hello, World" text in the top-left corner of the Stage:
 
// frame action for script 1 import flashx.textLayout.elements.TextFlow; import flashx.textLayout.elements.ParagraphElement; import flashx.textLayout.elements.SpanElement; import flashx.textLayout.factory.TextFlowTextLineFactory; import flash.geom.Rectangle; import flash.text.engine.TextLine; // Creating and structuring a TextFlow object var myFlow:TextFlow = new TextFlow(); var paragraph:ParagraphElement = new ParagraphElement(); var span:SpanElement = new SpanElement(); span.text = "Hello, World"; paragraph.addChild(span); myFlow.addChild(paragraph); // Creating a TextLine object from the TextFlow object var factory:TextFlowTextLineFactory = new TextFlowTextLineFactory(); factory.compositionBounds = new Rectangle(0, 0, 100, 25); factory.createTextLines(onCreateTextLines, myFlow); // the callback function: processing the generated TextLine object function onCreateTextLines(myTextLine:TextLine):void { addChild(myTextLine); }

 
Applying formatting to text content

To apply formatting to TLF text content, you'll use the TextLayoutFormat class. To learn more about formatting TLF text, see Controlling the appearance of text elements with the Text Layout Framework. As shown in the code example below, setting a TextLayoutFormat object to the TextFlow.hostFormat property defines the default format for the whole story (the formatting applied to the entire text content):
 
// add to the last frame action import flashx.textLayout.formats.TextLayoutFormat; var my_fmt:TextLayoutFormat = new TextLayoutFormat(); my_fmt.fontFamily = "Impact"; my_fmt.fontSize = 24; myFlow.hostFormat = my_fmt;
Add the code snippet above to the last frame action (script 1) to apply the formatting to the "Hello, World" text content. Choose Control > Test Movie to see the SWF file display the TLF text on the Stage (see Figure 2).
 
The font family and font size formatting properties are applied to the TLF text content.
Figure 2. The font family and font size formatting properties are applied to the TLF text content.
In addition to setting formatting for the entire text object, you can apply formatting to a specific element. All element classes inherit from the FlowElement class, so you can assign a TextLayoutFormat object to their instances' FlowElement.format properties. Similar to the cascading effect in CSS, the default formatting is applied to all properties in the story that are not set by the child element's formatting.
 
The code example below (script 2) divides the text content into two SpanElement instances. Then, it sets the default format to the whole story and applies different formatting to a single SpanElement instance:
 
// frame action for script 2 import flashx.textLayout.elements.TextFlow; import flashx.textLayout.elements.ParagraphElement; import flashx.textLayout.elements.SpanElement; import flashx.textLayout.factory.TextFlowTextLineFactory; import flash.geom.Rectangle; import flash.text.engine.TextLine; import flashx.textLayout.formats.TextLayoutFormat; var myFlow:TextFlow = new TextFlow(); var paragraph:ParagraphElement = new ParagraphElement(); var span:SpanElement = new SpanElement(); // dividing a text content var span2:SpanElement = new SpanElement(); // into two SpanElement instances span.text = "Hello, "; span2.text = "World" paragraph.addChild(span); paragraph.addChild(span2); myFlow.addChild(paragraph); var factory:TextFlowTextLineFactory = new TextFlowTextLineFactory(); factory.compositionBounds = new Rectangle(0, 0, 240, 25); // setting the default format to the whole story var my_fmt:TextLayoutFormat = new TextLayoutFormat(); my_fmt.fontFamily = "Impact"; my_fmt.fontSize = 24; myFlow.hostFormat = my_fmt; // applying a format to a specific element var my2_fmt:TextLayoutFormat = new TextLayoutFormat(); my2_fmt.fontFamily = "Helvetica"; my2_fmt.color = 0x0000FF; span2.format = my2_fmt; // creating a TextLine object from a TextFlow object factory.createTextLines(onCreateTextLines, myFlow); function onCreateTextLines(myTextLine:TextLine):void { addChild(myTextLine); }
Note: It's important not to call the TextFlowTextLineFactory.createTextLines() method before the default formatting settings for the text content have been applied.
 
Choose Control > Test Movie to see the SWF file display the TLF text content on the Stage. In this example, the Impact font family and a 24-point font size have been applied to the whole story as the default formatting. One element (the word World) has the element-specific formatting applied. It displays the Helvetica font in a blue (0x0000FF) color. However, the unique element's font size remains 24 points, as specified by the default formatting (see Figure 3).
 
The default formatting affects the font size for the entire story; the element-specific formatting causes the word "World" to appear with a blue Helvetica font.
Figure 3. The default formatting affects the font size for the entire story; the element-specific formatting causes the word "World" to appear with a blue Helvetica font.
You can create new TextLayoutFormat instances based on the formatting applied to other elements by using the TextLayoutFormat() constructor with its FlowElement.format passed as the argument.
 
This is the syntax to use when working with the TextLayoutFormat constructor:
 
var my_fmt:TextLayoutFormat = new TextLayoutFormat(span.format);
The FlowElement class contains most of the same properties as the TextLayoutFormat class, and the classes of the story's elements inherit the FlowElement class properties. The FlowElement class and the TextLayoutFormat class both implement the ITextLayoutFormat interface, so you can apply formatting properties without requiring the use of a TextLayoutFormat object. The code example below illustrates how to set the text content and the formatting:
 
var span:SpanElement = new SpanElement(); span.text = "Hello, World"; span.fontFamily = "Impact"; span.fontSize = 24;
Because the TextFlow class inherits the FlowElement class, it also uses the FlowElement.format property. If the TextFlow format property and the TextFlow.hostFormat property are both set, the TextFlow.hostFormat setting is treated as the higher definition. This means if the two properties are set and contain conflicting formatting properties, the lower definition (FlowElement.format) takes precedence and is applied to the TextFlow object.
 
Although you can specify both the formatting and the text content in the same function, it is a best practice to separate the code for each task. This strategy allows you to implement some of the more advanced features of the Text Layout Framework, as described later in this article. Additionally, if you use separate functions to set the structured text data and apply the text formatting, you'll find that your projects are easier to update and maintain in the future.
 

 
Creating a TextFlow object from XML data of Text Layout Framework Markup

Text Layout Framework Markup allows you to display the highest fidelity representation of text in a TextFlow object because the markup language includes attributes for all formatting properties available in the TextLayoutFormat class. And you can use XML data to populate a TextFlow object. To accomplish this, you'll use Text Layout Framework Markup to generate the markup language. And then you'll use the TextConverter.importToFlow() static method to convert the XML data into a TextFlow object.
 
The TextConverter.importToFlow() method requires two arguments to supply the source data and its format. The first argument can be an XML object if the source is XML data. The second argument must be one of the three TextConverter constants: TEXT_FIELD_HTML_FORMAT, PLAIN_TEXT_FORMAT, or TEXT_LAYOUT_FORMAT. To learn more about using the TextConverter, see the Importing Text section of the Text Layout Framework Model documentation. Pay close attention when reviewing the help because the sample script for the TextConverter.HTML_FORMAT contains an error. (Scroll to the bottom of that page to see the correct syntax to use for that example.) However, the code example provided for the TextConverter.TEXT_FIELD_HTML_FORMAT on the same page is correct.
 
When using Text Layout Framework Markup, you can set a format constant like this:
 
TextConverter.TEXT_LAYOUT_FORMAT
This is the syntax to use when working with the TextConverter.importToFlow() method:
 
TextConverter.importToFlow(source, format)
Table 2 describes the three format TextConverter constants in more detail.
 
Table 2. TextConverter constants
 
Constant
 
Data format
 
Description
 
HTML
 
The HTML format supports a subset of the tags and attributes supported by the TextField class
 
Plain text
 
A simple and unformatted string
 
Text Layout Framework Markup
 
See the Text Layout Framework Markup documentation
 
To create the same TextFlow object created in script 1 of this article, XML data formatted as Text Layout Framework Markup should be passed to the TextConverter.importToFlow() method. It's important to note that an XML name space ( xmlns attribute) must be declared in the root element of the script, as shown below:
 
import flashx.textLayout.conversion.TextConverter; var markup:XML = <TextFlow xmlns='http://ns.adobe.com/textLayout/2008'><p><span>Hello, World</span></p></TextFlow>; var myFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT);
A string of XML data can be passed as an argument to the TextConverter.importToFlow() method to convert it to a TextFlow object. Here's an example:
 
var markup:String = "<TextFlow xmlns='http://ns.adobe.com/textLayout/2008'><p><span>Hello, World</span></p></TextFlow>"; var myFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT);
As I mentioned previously, you must declare an XML name space ( xmlns attribute) in the root element. Without an XML name space in XML data, the TextConverter.importToFlow() method seems to return a null value. Both of the sample scripts dealing with XML data in the Importing Text and Displaying Content with Flow Composer sections of the Text Layout Framework View help documentation do not include declaration of the xmlns attribute but it is required. Be sure to declare the XML name space when incorporating XML data in your TLF projects. The corrected code example is posted on the JActionScripters site.
 

 
Displaying content with a flow composer

In addition to using the TextFlowTextLineFactory.createTextLines() method to create a TextLine instance from a TextFlow object and display it on the Stage (as I described earlier in this article), you can also use a flow composer. The advantage of using a flow composer is that you can enable the user to select and edit the text content in a SWF file. Conversely, TextFlowTextLineFactory is simple to use and consumes less memory. For these reasons, use the TextFlowTextLineFactory when displaying static text that does not require user interaction. See the section titled Displaying Content with TextFlowTextLineFactory for more information.
 
To use a flow composer, you'll need to call three methods. First, you'll use the ContainerController() constructor method to create its instance. The constructor method requires three arguments. The first argument is a Sprite instance (named container) used to store and display the created TextLine object. The other two arguments are the width and height of the text area, respectively (the default setting is 100 x 100 pixels).
 
Use the following syntax when calling the ContainerController() constructor:
 
new ContainerController(container, width, height)
The second method to call is the IFlowComposer.addController() method. Use the TextFlow.flowComposer property to associate the TextFlow object with the Sprite instance. A ContainerController instance is passed as the argument to the method to serve as a reference between the two objects. The value returned by the method is void.
 
Use the following syntax when calling the IFlowComposer.addController() method:
 
textFlow.flowComposer.addController(ContainerController)
The third method to call is the IFlowComposer.updateAllControllers() method, which composites and displays the text content.
 
Note: The sample script in Displaying Content with Flow Composer has the statement calling the updateAllContainers() method, but that method does not exist. The example should be rewritten to use the updateAllControllers() method. See the corrected code sample posted on the JActionScripters site to review the syntax to use.
 
A new TextLine object is created and replaced with the child instance contained in the Sprite instance. The method returns a value of true when the text content is successfully updated.
 
Use this syntax when calling the IFlowComposer.updateAllControllers() method:
 
textFlow.flowComposer.updateAllControllers()
To see how the three methods work together, examine the script below. This code example creates a TextLine instance from a TextFlow object and places it on the timeline:
 
var controller:ContainerController = new ContainerController(this, 240, 25); myFlow.flowComposer.addController(controller); myFlow.flowComposer.updateAllControllers();
To get a better understanding of how these pieces fit together, see the flow chart in Figure 4.
 
Relationship between a TextFlow, a container Sprite, and a ContainerController.
Figure 4. Relationship between a TextFlow, a container Sprite, and a ContainerController.
The code example below (script 3) creates a TextFlow object from XML data formatted as Text Layout Framework Markup, and then displays the text content with a flow composer:
 
// frame action for script 3 import flashx.textLayout.elements.TextFlow; import flashx.textLayout.formats.TextLayoutFormat; import flashx.textLayout.conversion.TextConverter; import flashx.textLayout.container.ContainerController; import flashx.textLayout.compose.IFlowComposer; // variable declaration and initialization var markup:XML = <TextFlow xmlns='http://ns.adobe.com/textLayout/2008'><p><span>Hello, World</span></p></TextFlow>; var myFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); var my_fmt:TextLayoutFormat = new TextLayoutFormat(); var controller:ContainerController = new ContainerController(this, 240, 25); var composer:IFlowComposer = myFlow.flowComposer; // IFlowComposer reference // setting the default format my_fmt.fontFamily = "Impact"; my_fmt.fontSize = 24; myFlow.hostFormat = my_fmt; // updating text content by a flow composer composer.addController(controller); composer.updateAllControllers();
This code stores the reference of the TextFlow.flowComposer property into a variable in order to work with it later. The property reference is actually an instance of the StandardFlowComposer class implementing the IFlowComposer interface. Therefore, the methods actually called are StandardFlowComposer.addController() and StandardFlowComposer.updateAllControllers(). For the time being, the class implementing the IFlowComposer interface is the only StandardFlowComposer class. According to the help section titled Displaying Content with Flow Composer, however, "In the future, new classes could be added to the framework that also implement IFlowComposer."
 
When you choose Control > Test Movie, the SWF file displays the "Hello, World" text using the same formatting as before, and displays it in the top-left corner of the Stage (see Figure 5).
 
The font family and font size formatting properties are applied to the TLF text content.
Figure 5. The font family and font size formatting properties are applied to the TLF text content.

 
Understanding the organization of classes in Text Layout Framework

The Text Layout Framework consists of many classes categorized into several packages in order to provide complex functionality and control over the display of text content. The classes described in this article handle the following three tasks:
 
  • Structuring text content
  • Formatting text content
  • Displaying text content
The classes in the first set are used to create structured text content (also known as a story). Classes in the flashx.textLayout.elements package are used to create instances of elements and structure them. You'll use the TextFlow, ParagraphElement and SpanElement classes to create structured text. Additionally, you can use the TextConverter.importToFlow() method to convert text data to a story, as described earlier in this article in the section on working with the Text Layout Framework Markup.
 
The classes in the second set are used to apply formatting to the text content. You'll use the TextLayoutFormat class to control the appearance of the text content.
 
The classes in the third set are used to display text content on the Stage. You'll create a TextLine instance (that inherits from the DisplayObject class) and place it into a container. The easiest way to do this is to create a TextLine instance using the TextFlowTextLineFactory.createTextLines() method. When your project requires more precise control of the displayed text, you'll use a flow composer that associates a TextFlow object with a container and displays them.
 
There are two reasons why the classes in the Text Layout Framework are divided this way. The first reason has to do with compartmentalization. Each class performs a specialized task and its capabilities can be easily extended. The second reason is based on offering functionality using a strategy consistent with other formatting languages, such as CSS and HTML. Since the classes are in separate packages, the code used to define the data structure can be independent from the code used to specify the formatting and update the text's appearance.
 
The classes described in this article comprise a very small portion of the entire Text Layout Framework library. See the section titled Using the Text Layout Framework in the Adobe Flash Platform Help documentation for more details. The section linked above explains the framework with the model-view-controller (MVC) design pattern. To learn more about this development technique, read the Model-View-Controller article on Wikipedia.
 
In this example, the classes responsible for structuring text content and formatting text content are part of the Model design pattern. The classes responsible for displaying text content correspond to the View design pattern. None of the classes described in this article relate to the Controller because this set of classes handle user interaction with the SWF file.
 

 
Where to go from here

The concepts described in this article are just scratching the surface of what is possible using the Text Layout Framework. You can display global languages in the desired orientation (vertically and right-to-left) and add advanced typography effects to text characters. Experiment with displaying the TLF text in columns and loading in XML data from an external file. You can also enable interactivity with the text content to allow users to select and edit the TLF text in a dynamic text field in the SWF file.
 
To learn about working with the TLFTextField class, see my other article, Controlling the appearance of text elements with the Text Layout Framework, on the Adobe Developer Connection. Also visit the ActionScript Technology Center and the Flash Developer Center to get more information and sample projects.