Home  >  

Utilizing Flash Text Layout Framework using MXML tags

Author photo
AddThis Social Bookmark Button
Flash Text Layout Framework (TLF) Created by the InDesign team (http://labs.adobe.com/technologies/textlayout/), TLF is Adobe’s new Flash framework for dealing with text. The TLF can be used in Flash CS4, Flex 3.2 and Flex 4 SDK The new framework consists of a set of classes in Flash Player 10 that brings print-quality graphics to the Web and AIR application and allows you to create multilingual web applications using device fonts.

There are already few articles out there that gives examples and show how to work with pure action script to utilize TLF, however I didn't find any article that cover TLF using MXML tags so I decided to post this article.
Here are some of TLF features:

  • Bidirectional text: Includes vertical text and over 30 writing systems including Arabic, Hebrew, Chinese, Japanese, Korean, Thai, Lao, the major writing systems of India, Tate-Chu-Yoko (horizontal within vertical text) and more.
  • Formatting: Text with inline graphics (images, SWFs, or any DisplayObject) and multiple columns of text with text flow and text selection through these columns. Additionally support for vertical text, Tate-Chu-Yoko (horizontal within vertical text) and justifier (Eastern European).
  • Print-quality typography for the web: Allows for kerning, ligatures, typographic case, digit case, digit width, and discretionary hyphens.
  • Mouse and Keyboard user gestures - standard keyboard and mouse functionality for copy, paste, undo and cut.
  • Text metrics: Includes measurements and offsets of fonts

The architecture of the framework is shown below. The TLF is the high-level implementation of the Flash Text Engine (FTE). The FTE is a low-level API, so you can come up with you own set of components for FTE. FTE is limited in functionality and offers basic manipulation of text and is the foundation for the TLF.

TLF1.jpg

In Flash Builder 4 there are two SWC library that include and provide the support for FTE: framework_textLayout.swc and textLayout.swc.

  • framework_textLayout.swc - includes classes to allow components such as DataGrid or TextField to support TLF.
  • textLayout.swc - include the entire class library to support TLF.

Since the last built of Flash Gumbo, which was given at Adobe MAX 2008 and is available on the pre-release Adobe site, the TLF and components such as TextBox, TextElement or content components have been changed and they are no longer available. The best way to check the TLF version is using the BuildInfo class as follow:

trace("TLF version: " + BuildInfo.VERSION);
trace("TLF Build number: " + BuildInfo.kBuildNumber);
trace("TLF Audit id: " + BuildInfo.AUDIT_ID);
I am using the Flash Builder 4 Beta and I got the following version:

TLF version: 1.0
TLF Build number: 427 (699527)
TLF Audit id: <AdobeIP 0000486>

Based on the TLF architecture we can use the following to create, format and control our text components:

Flex Components:

  1. GraphicElement - graphic element in a TextBlock or GroupElement object extends ElementFormat and offers limited manipulation of the text. It supports UIComponent-style layout and invalidation capability.
  2. simpleText - lightweight text that mostly uses the FTE and some of the TLF classes it extends GraphicElement and provide limited functionality. Since it’s of GraphicElement type UIComponent can have few simpleText objects share the same DisplayObject.
  3. RichText - can be used to replace the . Supports all TLF text formats and can draw background but not a border. Text can be in horizental and vertical but cannot be scrolled. Text can also be truncated and show “…” for the missing text.
  4. RichEditableText - can be used to replace the . Heavyweight class compares to simpleText and RichText and support TLF and all the features mentioned in RichText. Additionally, it also supports hyperlinks, border, background, scrolling, selection, and editing.
  5. TextFlow - TextFlow element is the root of a TLF text object model.
  6. FlowElement - TextFlow holds the FlowElements.

Pure ActionScript classes:

  1. contentElement - holds content such as text or graphic of the textBlock
  2. ElementFormat - represent the format of the contentElement
  3. fontDescription - represent properties of the font applied to the elementFormat
  4. TextBlock - represent the factory for creating a paragraph of text
  5. textLine - displayObject used for creating a line of text for the textBlock
TLF primitive Flex components:

There are three text primitives that you can use: SimpleText, RichText, and RichEditableText. Let’s take a simple example using Flex 4 Beta SDK:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768">
		
		<s:Group fontSize="12" height="242.936" width="383.055">
		<s:RichText rotation="12" alpha="0.8" x="50" y="50">
			<s:TextFlow color="0x555555">
		   		<s:p>
				<s:span fontWeight="bold">Just text</s:span>
				<s:br />
				<s:a href="http://twitter.com/eladnyc">Elad Elrom</s:a>
				</s:p>
			</s:TextFlow>
		</s:RichText>
		
	</s:Group>
</s:Application>

simpleText element, which extends the GraphicElement and uses the FTE, and thus offers limited manipulation of the text.

<s:SimpleText fontSize="12" width="100"> Hello, world!</s:SimpleText>

Using TLF-based components, you have more control over text, and you can set fonts properties such as style, alpha, anti-aliasing, and rotation values, as well create custom text components.

<s:RichText fontFamily="arial" color="0x4697c4" text="RichText"  />

The most advanced text component is RichEditableText, it extends the UIComponent and uses the TLF API. However, it is also the most heavyweight and costly of the three text primitives, since it’s based on UIComponent. Take a look at the following code:

<s:RichEditableText fontFamily="arial" color="0x4697c4" text="RichEditableText" />
Notice that we the RichEditableText and RichText are UIComponent, we don’t need to place them in the Group element. Also, once you compile, you will notice that RichEditableText text by default will be scrollable, selectable, and editable.

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768">

     <s:RichEditableText fontFamily="arial" color="0x4697c4" text="RichEditableText"  x="0" y="18"/>
     <s:RichText fontFamily="arial" color="0x4697c4" text="RichText"  />     

</s:Application>
TextFlow and FlowElement

The TLF's component object model is a tree of FlowElements such as ParagraphElements and SpanElements (corresponding to tags). What TLF essentially does is create, render or manipulate the TextFlows classes. SpanElements tags available for you can be seen here:

  • a tag - used to embed a link. Can include: br, img, span, tcy, tab or tags.
  • br tag - used to add a break. Text will continue to the next line.
  • div tag - used for division of the text. Inner tags can include div or p tags.
  • img tag - used for adding an image in a paragraph
  • p tag - a new paragraph, can include all the elements other than div.
  • span tag - used to create a run of text in a paragraph; can contain only a text tag.
  • tab tag - used to add a tab character to the paragraph.
  • tcy tag - used in vertical text to run an horizontal text. Can be used for languages such as Japanese. Can contain the following tags: code, break, img, span, tab, code.

Take a look at an example, which uses the RichText primitive components as well as SpanElements and TextFlow element. The example will use the RichText primitive components and add customozation.

     <s:Group fontSize="12">
	<s:RichText rotation="12" alpha="0.8" x="50" y="50">
	          <s:TextFlow color="0x555555">
             	                 <s:p>
                                      <s:span fontWeight="bold">Just text</s:span>
                                      <s:br />
                                      <s:a href="http://twitter.com/eladnyc">Hello World</s:a>
             	                 </s:p>
                        </s:TextFlow>
               </s:RichText>
     </s:Group>
Notice that, in this example, we have a RichText that has a TextFlow element. The TextFlow element is the root of a TLF text object model. The TextFlow holds FlowElements such as the ParagraphElements p element, the SpanElements span element, or the ImageElement img element. Essentially, the TLF creates, renders, manipulates, and edits TextFlow elements.

Spark TextArea

Up until Flex 4 Beta Flex offers out of the box rich text editor called RichTextEditor. It was not that rich since it was very hard to control and manipulate many of the features needed to create a rich text editor. To create the editor you can just type the following element:
<mx:RichTextEditor fontFamily="arial" color="0x4697c4" text="RichTextEditor"/>
Flex 4 Beta Flex offers TextArea which is based on TextBase which extends SkinnableComponent and is another Flex 4 core class. It is used as the base class for all the skinnable components, such as Spark TextInput. Each skinnable component includes a TextView in its skin. It is also part of Adobe’s effort to rework the component and separate the view, model, and logic to allow a better manipulation and the ability to move to design-centric development.

Let’s create an example that uses the Spark TextArea component and gives the user control over some of the text properties, see complete code example below: TLF2.jpg

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
	xmlns:s="library://ns.adobe.com/flex/spark" 
	xmlns:mx="library://ns.adobe.com/flex/halo" 
	minWidth="1024" minHeight="768"
	initialize="initializeHandler(event)">

	<fx:Script>
		<![CDATA[

			import flash.text.engine.FontDescription;
			import mx.events.FlexEvent;

			[Bindable]
			private var fontDataProvider:Array = new Array();
		
			private function exportText(evt:Event):void
			{
 				exportTextArea.text = textArea.export().toXMLString();
 			}
			
			protected function initializeHandler(event:FlexEvent):void
			{
 				var allFonts:Array = Font.enumerateFonts(true);
 				
 				for (var i:int = 0; i < allFonts.length; i++) 
 				{
  					if (allFonts[i].fontType == "device") 
  						fontDataProvider[i] = allFonts[i].fontName;
  				}
 			}

		]]>
	</fx:Script>

	<s:HGroup height="408" width="599" left="15" top="5">
		
		<s:VGroup height="400">
		
			<mx:HSlider id="widthSlider"
				labels="Width:"
				minimum="50"
				maximum="100"
				value="250"
				snapInterval="1"
				liveDragging="true"/>
		
				<mx:HSlider id="indentSlider"
					labels="Indent:"
					minimum="0"
					maximum="100"
					value="0"
					snapInterval="1"
					liveDragging="true"/>
			
				<mx:HSlider id="textAlphaSlider"
					labels="Text alpha:"
					minimum="0"
					maximum="100"
					value="100"
					snapInterval="1"
					liveDragging="true" />				

				<mx:HSlider id="marginTopSlider"
					labels="Margin top:"
					minimum="0"
					maximum="100"
					value="0"
					snapInterval="1"
					liveDragging="true" />

				<mx:HSlider id="fontSizeSlider"
					labels="Font size:"
					minimum="0"
					maximum="100"
					value="16"
					snapInterval="1"
					liveDragging="true" />
					
				<mx:ComboBox id="fontFamilyComboBox" dataProvider="{fontDataProvider}" selectedIndex="1"/>
				
				<s:HGroup>
					<s:SimpleText text="align: " />
					<mx:ComboBox id="alignComboBox" dataProvider="[start,end,left,center,right,justify]" selectedIndex="1"/>
				</s:HGroup>
			
			<s:Button id="exportButton" width="200"
				label="export"
				click="exportText(event);"/>

		</s:VGroup>

		<s:VGroup width="336" height="400">
				
				<s:TextArea id="textArea"
					textAlpha="{textAlphaSlider.value/100}"
					fontFamily="{fontFamilyComboBox.selectedItem}"
					textAlign="{alignComboBox.selectedItem}"
					textIndent="{indentSlider.value}"
					fontSize="{fontSizeSlider.value}"
					percentWidth="{widthSlider.value}"
					height="297" width="100%">
	
				   <s:content>
					  <s:p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed</s:p>
					  <s:p>incididunt ut labore et dolore magna aliqua. Ut enim ad minim</s:p>
					  <s:p>exercitation ullamco laboris nisi ut aliquip ex ea commodo</s:p>
					  <s:p>dolor in reprehenderit in voluptate velit esse cillum dolore eu</s:p>
					  <s:p>Excepteur sint occaecat cupidatat non proident,  fugiat nulla</s:p>
					  <s:p>sunt in culpa qui officia deserunt mollit anim id est laborum.</s:p>
				   </s:content>
	
			   </s:TextArea>
	
				<s:TextArea id="exportTextArea"
					width="100%" height="83"/>
		</s:VGroup>
			
	</s:HGroup>

</s:Application>

Few things to notice.

The exportText method uses the toXMLString property, which can export the contents of a Flex 4 TextArea control. In our case, we will post the results in another text area component. initializeHandler method create an array that contain a list of all the available fonts names so we can use them on in a drop down menu.


                  private function exportText(evt:Event):void
                  {
                         exportTextArea.text = textArea.export().toXMLString();
                   }

TextArea allows controlling white space, such as indenting and line breaks; the following slider controls the indent property in the TextArea component:


<mx:HSlider id="indentSlider"
                              labels="Indent:"
                              minimum="0"
                              maximum="100"
                              value="0"
                              snapInterval="1"
                              liveDragging="true"/> 

Margins of text in all directions can be controlled using marginLeft, marginTop, marginRight, and marginButton, as illustrated in the following example code:


<mx:HSlider id="marginTopSlider"
      labels="Margin top:"
      minimum="0"
      maximum="100"
      value="0"
      snapInterval="1"
      liveDragging="true" /> 

To read more about TLF see Adobe wiki:
http://opensource.adobe.com/wiki/display/flexsdk/Spark+Text+Primitives#SparkTextPrimitives-content

Click here to follow Elad Elrom on Twitter

Read more from Elad Elrom. Elad Elrom's Atom feed

Comments

4 Comments

Charles said:

Wow. good start

This is a really great summary of using TLF in Flex. Serious kudos for distilling everything down so well.

One caveat for those new to working we TLF in MXML. Be aware that empty paragraphs and spans will get normalized out of a TextFlow on compose. If you have an ID reference to them, they will still exist, but they won't be part of the flow.

This problem can occur when trying to use TLF TextFlows as multifield 'templates' for visual components, such as item renderers.

Hi, after reading this about flash text layout I think you might be able to answer my question at
http://forums.adobe.com/thread/474696;jsessionid=0EA586902ABA5F25896B509DEFC91192.node0?tstart=0

What I want to do is I want a red box to appear around some text in my s:TextArea, which is editable.

kiran kumar said:

hi Elad Elrom
It's a grate article.
I have a problem in TLF , i want to display text as ordered list as HTML

    tag does. I try to get this by working with api s i sort out some extend but its not fully functioning. here is wat i tryed

private function numberedBullets(e:Event):void
{
var textArea:TextArea = rte.textArea;
var tf:TextFormat = new TextFormat();
//var textField:IUITextField = textArea.mx_internal::getTextFiled();

var beginIndex:int = textArea.mx_internal::getTextField().selectionBeginIndex;
var endIndex:int = textArea.mx_internal::getTextField().selectionEndIndex;

if (beginIndex == endIndex)
{
tf= new TextFormat();
}

beginIndex = textArea.mx_internal::getTextField().getFirstCharInParagraph(beginIndex) - 1;
beginIndex = Math.max(0, beginIndex);
endIndex = textArea.mx_internal::getTextField().getFirstCharInParagraph(endIndex)+textArea.mx_internal::getTextField().getParagraphLength(endIndex) - 1;

var textRange:TextRange = new TextRange(textArea,true,textArea.selectionBeginIndex, textArea.selectionEndIndex);
//textRange.text = bulletIndx++ +" . "+textRange.text;
textRange.bullet = false;

var noOfTextLines:int = textArea.mx_internal::getTextField().numLines;
var tempString:String = "";
for(var i:int = 0; i {
tempString += bulletIndx++ +" . "+ textArea.mx_internal::getTextField().getLineText(i);
}

textRange.text = tempString;
tf.indent = 20;
textArea.mx_internal::getTextField().setTextFormat(tf);


}


can you help me out how to get this .
Please suggest me . it's important for me

Thanks
kirankumar

Leave a comment


Tag Cloud

Question of the Week: Dream App

If you had an unlimited budget and unlimited resources what application would you build and why would you build it?

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.