搜索

  •  

在Flex 3.2 和 AIR 1.5 中使用文字布局框架

出自9RIA.com WIKI

跳转到: 导航, 搜索

原文:Using the Text Layout Framework in Flex 3.2 and AIR 1.5
作者:Mihai Corlan
译者:rainfly
发表于:2009年2月16日
用户范围:中级
产品:Flex
点击此处查看或参与讨论吧^_^点击此处查看或参与讨论吧^_^

目录

说明

本文目的在于介绍针对Adobe Flash Player 10 和 Adobe AIR 1.5 的文字布局框架,并演示如何在Adobe Flash Player 10 和 Adobe AIR 1.5运行时展示富文本。我不会涵盖这个框架的所有功能,但是给你足够的帮助。

需要的资源

你需要下面的软件及文件,才能学习本文:

注意: 可以通过Flex Builder中的菜单File > Import > Flex Project,把example_text_layout_framework.zip导入进去。

如果你使用的Flex Builder的SDK不是3.2版的,你可以下载3.2版的SDK并把它添加到Flex Builder中

前提知识

你应该熟悉Flex,XML,ActionScript 3.0以及Flex Builder才能更好的理解本文内容。

关于文字布局框架库

Flash Player 10 和 Adobe AIR 1.5中的Flash文字引擎,支持许多新的文字功能。

这就是文字布局框架的来历。它是用纯ActionScript编写的库,因此可以用于Flash CS4,Flex 3.2,“Gumbo”(下一代Flex的代码名字),以及Adobe AIR 1.5。

文字布局框架支持下列功能:

  • 双向文字,垂直文本以及超过30种书写系统,包括阿拉伯语、希伯来语、中文、日语、韩语、泰语、老挝语,及印度的主要语言。
  • 选择、编辑,以及把文字放入到多列或多个容器里,当然还有环绕在内嵌的图片周围。
  • 垂直文本,纵中横(水平、垂直文字混排),以及支持东亚印刷格式。
  • 多种排版控制,包括字符调整,连字,排版样式,数字样式,数字宽度,和连字符。
  • 剪切、复制、粘帖、撤消以及用键盘鼠标进行编辑。
  • 有丰富的开发者API用来操作文字内容、布局和标记,也可以创建自定义的文字组件。

图1至6是使用文字布局框架创作的示例的截图,可以从Adobe Labs获得该示例。

fig01.jpg

图 1. 日语文字,从左到右,垂直;并且你能看到选中的文字。

fig02.jpg

图 2. 文字分布在连接的容器里。

fig03.jpg

图 3. 格式化文本:方向,对齐,旋转,间隔。

fig04.jpg

图 4. 多列分布。

fig05.jpg

图 5. 内嵌的图片。

fig06.jpg

图 6. 文本混合及特效。

认识这些组件及其功能

文字布局框架库由3个组件和10个包组成。所有的包都是flashx.textlayout包的子包。因为这个库使用纯ActionScript 3.0脚本编写的,因此它可以用在Flash CS4, Flex 3.2,Gumbo(这个库是Gumbo的一部分),AIR 1.5,当然还有Flash Player 10中。下面是关于文字布局框架库中的3个组件的简单介绍:

  • textLayout_core.swc是主组件,它负责数据存储、把文字分布到多个容器中,并渲染容器。
  • textLayout_conversion.swc用来把文字导入到框架中,也负责把文字导出。
  • textLayout_edit.swc文字选定和编辑。

文字布局框架的MVC结构

了解文字布局框架库的一个方式是把它跟MVC模型比较:

  • model主要由flashx.textlayout.elements包定义,该包中的类/接口用来定义存储文字的数据结构。

另一个包,flashx.textlayout.formats用来存储文本格式化信息。 flashx.textlayout.conversion包可以看作模型的一部分,因为它包含导入和导出数据的规则。

  • view 包含3个包,用来渲染显示的文字。你可以使用2种不同方法中的一个显示文本:使用

flashx.textlayout.factory</kbd> 包可以显示静态文本;使用<code>flashx.textlayout.container 可以显示包含动态文本的容器。<kbd>flashx.textlayout.compose</kbd>包定义了在容器中定位和显示动态文本的方法。

  • controller由2个包flashx.textlayout.editflashx.textlayout.operations组成,

它定义了用户如何跟文字交互(选定、编辑、复制和粘帖、撤消等等)。


TextFlow的层次模型

该模型使用一个分层树表示文本。树中的每个元素都是flashx.textlayout.elements包中的一个类。 根元素总是TextFlow类的一个实例,在概念上它表示文本story(词语story来自DTP,意思是文本集应该看作一个单元来处理)。 比如,你正在读的文章就是一个story。

其它的元素有:

  • div: 层,只能包含div或p元素
  • p: 段落,可以包含除了div之外的任何元素。
  • a: 链接;可以包含tcy, span, img, tab, br
  • tcy: 垂直文本中的连续横向文字;比如在日语中你就会用到这个元素;可以包含a, span, img, tab, br
  • span: 段落中的连续文字;只能包含文本。
  • img: 段落中的图片
  • tab: 一个制表符
  • br: 一个断行符;文字会从下一行继续,但是它并不开始一个新的段落。

TextFlow类只能用div 和p这两种元素作为子元素。图 7 展示了一个story模型的大概样子。

fig07.jpg

图 7. 文字布局模型

可以用文字布局框架标记把这个结构转化为一个XML文档。节点可以是:TextFlow, div, p, a, img, span, tcy, br 和 tab。同时,每个节点都有与之对应的ActionScript类:TextFlow, DivElement, ParagraphElement, LinkElement, TCYElement, SpanElement, InlineGraphicElement, TabElement 和 BreakElement。 这些类都直接或间接的继承自FlowElement类。

创建一个TextFlow元素

有两种方式创建一个TextFlow元素:可以使用XML对象或者先创建节点,再把它们编译成一个树(就像使用DOM创建XML对象一样)。

下面的代码演示了如何使用XML对象创建一个TextFlow元素:

private static const textInput:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008">
 
   <div>
      <p>
          <img source="air.png"/>
          <span>Flex is a highly productive, free open
          source framework for building and maintaining expressive web
          applications...</span>
          <br/>
      </p>
   </div>

 </TextFlow>;
 
private var textFlow:TextFlow = TextFilter.importToFlow(textInput, TextFilter.TEXT_LAYOUT_FORMAT);

需要说明的是TextFilter类用来导入XML对象;它创建TextFlow的一个实例。import方法的第二个参数决定了这个XML对象是以怎样的格式被写入的。 在本例中使用的是文字布局框架标记。

下面的小片段演示了使用FlowElement类生成一个TextFlow元素:

var textFlow:TextFlow = new TextFlow();
var p:ParagraphElement = new ParagraphElement();
var span:SpanElement = new SpanElement();

span.text = "Hello, World!";
p.addChild(span);
textFlow.addChild(p);

格式化信息模型

前面提到过,这个模型也存储了格式化信息。如果你使用XML生成TextFlow元素,那么你就可以在节点上添加属性:

var text:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008"
fontSize="14" textIndent="15" marginBottom="15"
paddingTop="4" paddingLeft="4">"
 
<p>
<span>There are many </span> 
<span fontStyle="italic">such</span>
</p>
 
</TextFlow>;

或者,你使用FlowElement,那么可以像下面这样做:

var cf:CharacterFormat = new CharacterFormat();
cf.fontSize = 14;
textFlow.characterFormat = cf;

以被设置的属性分为3类:容器格式,段格式和字符格式。你可以在文档中查看关于flashx.textlayout.formats包的API。

  • 容器格式应用到文字的整个容器上,比如,column属性和padding值。容器格式只能应用到TextFlow,DivElement或其他实现了IContainerController接口的类上。你可以使用ContainerFormat 类的一个实例来应用这些属性。
  • 段落格式应用到一段文字中:自动调整, 边距, tab停靠位. 它们可以被用在TextFlow,DivElement和ParagraphElement类上。你可以使用ParagraphFormat 类的一个实例来应用这些属性。
  • 字符格式 仅仅作用于单个字符或连续的字符上:字体大小,颜色,间距, 字距调整, 上标。你可以把它们用在任何FlowElement上,因此你可以通过设置TextFlow元素或SpanElement的属性来设定整篇文章的字体大小。使用CharacterFormat类来设置属性。

当你把格式应用到FlowElement上,你有2个选择:覆盖原有的格式,还是在原有格式基础上添加新格式。下面的代码演示了这两种情况—要保持原有格式,在创建新格式的时候把原格式的实例传入到新格式的构造函数中:

// 覆盖TextFlow的characterFormat
var cf:CharacterFormat = new CharacterFormat();
cf.fontSize = 14;
textFlow.characterFormat = cf;
// 保持原有格式,仅改变字体大小
var cf:CharacterFormat = new CharacterFormat(textFlow.characterFormat);
cf.fontSize = 14;
textFlow.characterFormat = cf;

如果你改变了TextFlow元素的字号,那么它的所有没有明确指定字号的子元素都将使用新设定的字号。

要点: 每次你改变了已经显示的TextFlow对象的属性,都要调用flowComposer属性的updateAllContainers() 方法,这样才能更新显示:

textFlow.flowComposer.updateAllContainers();

显示文字

你已经知道了如何使用类TextFlow创建存储文本的模型。现在我们来看下如何显示这些文字。 通常来说,根据你对文本控制程度需求的不同,有2种方法可选。这两种方法都会把TextFlow类转化成 TextLine(新的Flash文字引擎的组成部分)的实例。为了显示TextLine实例,你需要把它添加到DisplayObjectContainer的子类中 ,比如Sprite。

TextLineFactory

如果你仅仅想显示文字而不需要同它交互(所谓交互,比如,选定文字),那么你可以使用TextLineFactory。 此类有2个静态方法, createTextLineFromTextFlowcreateTextLinesFromString, 它们使用TextFlow或者字符串生成TextLine对象。下面是一个例子:

var sprite:Sprite = new Sprite();
// 下面设定文字边界
var bounds:Rectangle = new Rectangle(0,0,300,100);
var txtStr:String = "This is sample text showing lines created by TextLineFactory.";
var characterFormat:CharacterFormat = new CharacterFormat();
characterFormat.fontSize = 48;
 
TextLineFactory.createTextLinesFromString(callback, txtStr, bounds, characterFormat);
 /* 下面是createTextLinesFormString()会调用的回调函数 */
 function callback(tl:TextLine):void{
       sprite.addChild(tl);
  }
FlowComposer

如果你想要选定或编辑文字,那么就要使用Flow Composer。每个TextFlow实例都有一个 实现了IFlowComposer接口的对象。你可以使用TextFlow的flowComposer属性访问该对象。 该对象把文字跟一个或多个容器关联起来并做好显示的准备。

任意DisplayObjectContainer 的实例都能用作容器,比如Sprite。为了把容器连接起来(这样,第一个容器显示不完的文字将会在后面的容器中显示)以支持滚动或容器格式化,把DisplayObjectContainer放到了DisplayObjectContainerController的实例中。

下面的例子演示了如何把容器添加到TextFlow对象中,然后触发格式化并显示文字:

var sprite:Sprite = new Sprite();
canvas.rawChildren.addChild(sprite);
var controller:IContainerController = new DisplayObjectContainerController(sprite, 600, 400);
textFlow.flowComposer.addController(controller);
textFlow.flowComposer.updateAllContainers();

使文字可选、可编辑

如果你想使文字可被选中,那么你需要使用一个管理器SelectionManager 并把它跟TextFlow类的interactionManager属性关联起来。 像下面这样设置管理器:

textFlow.interactionManager = new SelectionManager();

把管理器同TextFlow的interactionManager关联起来之后,TextFlow类就可以访问管理器的事件处理器。 比如,它知道什么时候按下了按键,什么时候容器失去或者获得了焦点,以及何时文字被选中了。

如果你想在可选定基础上还要可编辑,那么应该使用EditManager替代SelectionManager:

textFlow.interactionManager = new EditManager();

使用撤消和重做命令

如果想支持撤消/重做命令,像下面这样使用UndoManager  :

textFlow.interactionManager = new EditManager(new UndoManager());

导入、导出文本

使用<kbd>flashx.textlayout.conversion</kbd>包中的TextFilter对象完成导入和导出的操作。 在前面你已经看到了把XML导入到TextFlow的一种方法。你需要做的是:

var textInput:XML = <TextFlow><div><span>Some text here.</span></div></TextFlow>;
var textFlow:TextFlow = TextFilter.importToFlow(textInput, TextFilter.TEXT_LAYOUT_FORMAT);

当然也可以导入纯文字(通过把第二个参数设置成TextFilter.PLAIN_TEXT_FORMAT,就把转换器设置成解析字符串了):

var textInput:String = "Hello World, this is plain text";
var textFlow:TextFlow = TextFilter.importToFlow(textInput, TextFilter.PLAIN_TEXT_FORMAT);

文字布局框架可以导出3种格式的文字:纯文字、FXG和文字布局格式。 下面的例子演示的是如何从TextFlow实例中导出带格式的XML文字:

var out:XML = TextFilter.export(textFlow, TextFilter.TEXT_LAYOUT_FORMAT, ConversionType.XML_TYPE );

示例:在Flex和AIR中使用文字布局框架

接下来演示如何在Flex和AIR中使用文字布局框架库。

在Flex应用程序中使用这个框架

本例子使用flowComposer。我使用单个容器,textFlow根据XML文件生成。在这个XML文件中,有4个段落4种语言,其中的2个是从左到右显示,另外2个从右到左。另外,前两段还增加了对字号、列数、文字方向的控制。

fig08.jpg

图 8. 示例

你可以点击文字、滚动、编辑、删除、插入、撤消,复制/粘帖等等。

下面是源代码(别忘了你需要Flex SDK 3.2 和本框架的3个SWC库,这3个SWC文件包含在本文提供的那个压缩包里):

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:local="*" layout="absolute" creationComplete="init()"
horizontalScrollPolicy="off"
viewSourceURL="srcview/index.html">
<mx:Script>
    <![CDATA[
        import mx.controls.CheckBox;
        import mx.collections.ArrayCollection;
        import flashx.textLayout.formats.Direction;
        import flashx.textLayout.elements.InlineGraphicElement;
        import flashx.textLayout.events.StatusChangeEvent;
        import flashx.textLayout.formats.ContainerFormat;
        import flashx.textLayout.formats.ICharacterFormat;
        import flashx.textLayout.formats.CharacterFormat;
        import mx.events.SliderEvent;
        import flashx.textLayout.edit.UndoManager;
        import flashx.textLayout.edit.EditManager;
        import flashx.textLayout.container.DisplayObjectContainerController;
        import flashx.textLayout.conversion.TextFilter;
        import flashx.textLayout.elements.TextFlow;
        
        public var directions:ArrayCollection = new ArrayCollection(
             [
                  {label:"Left-to-Right", data:Direction.LTR},
                  {label:"Right-to-Left", data:Direction.RTL}
             ]
        );
        
        [Embed(source="air.png")]
        [Bindable]
        static publicvar imgClass:Class;
            
        private var _textContainer:Sprite = null;
        
        private staticconst textInput:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008">
<div>
    <p><span>and the text goes here ...</span></p>
</div>
</TextFlow>;
        
        privatevar _textFlow:TextFlow;
                                                
        privatefunction init():void {
            _textContainer = new Sprite();
            canvas.rawChildren.addChild(_textContainer);
 
            _textFlow = TextFilter.importToFlow(textInput, TextFilter.TEXT_LAYOUT_FORMAT);
            _textFlow.flowComposer.addController(new DisplayObjectContainerController(_textContainer, canvas.width-40, canvas.height));
           _textFlow.addEventListener(StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGED, picLoaded);
            //adding Select/Edit/Copy/Paste/Undo features
            _textFlow.interactionManager = new EditManager(new UndoManager());
            // initialize with a selection before the first character
            _textFlow.interactionManager.setSelection(0,0);
            _textFlow.flowComposer.updateAllContainers();
        }
                
        privatefunction picLoaded(event:StatusChangeEvent):void {
            var image:InlineGraphicElement = event.element as InlineGraphicElement;
            _textFlow.flowComposer.updateAllContainers();
        }
        
        privatefunction changeFontSize(event:SliderEvent):void {
            var cf:CharacterFormat = new CharacterFormat(_textFlow.characterFormat);
            cf.fontSize = event.value;
            _textFlow.characterFormat = cf;
            _textFlow.flowComposer.updateAllContainers();
        }
 
        privatefunction changeNoColumns(event:SliderEvent):void {
            var cf:ContainerFormat = new ContainerFormat(_textFlow.containerFormat);
            cf.columnCount = event.value;
            cf.columnGap = 15;
            _textFlow.containerFormat = cf;
            _textFlow.flowComposer.updateAllContainers();
        }
        
        privatefunction changeTextDirection(event:Event):void {
            _textFlow.direction = (event.target as ComboBox).selectedItem.data;
            _textFlow.flowComposer.updateAllContainers();
        }
 
    ]]>
</mx:Script>
    <mx:VBox x="20" y="20">
        <mx:Canvas id="canvas" width="600" height="400" backgroundColor="#ffffff" verticalScrollPolicy="auto"/>
        <mx:HBox width="100%">
            <mx:HSlider labels="Font size:" minimum="10" maximum="22" snapInterval="1" change="changeFontSize(event)" enabled="true" />
            <mx:HSlider labels="No of Columns:" minimum="1" maximum="2" snapInterval="1" change="changeNoColumns(event)" enabled="true" />
            <mx:Label text="Text Direction:"/>
            <mx:ComboBox change="changeTextDirection(event)" dataProvider="{directions}"/>
        </mx:HBox>
    </mx:VBox>
 
</mx:Application>

在AIR应用程序中使用本框架

如果想在AIR程序中使用文字布局框架库,按照下面的步骤来完成上面的例子:

  1. 创建一个AIR工程;确认你使用的是Flex SDK 3.2
  2. 把文字布局框架的3个SWC文件添加到libs文件夹中
  3. 把上面源代码中 mx:Application 节点之间的代码复制到AIR工程的MXML文件中。
  4. 确认你在 mx:WindowApplication节点上添加了xmlns:local="*" creationComplete="init()"

接下来做什么

如果你想了解更多文字布局框架库的知识,请访问Adobe Labs,在那里你可以看到示例程序(图1到图6展示的)。当你点击示例右上角的箭头时,可以下载当前面板的源代码, 学习它是如何做的。也可以看演示,从中你可以看到文字布局框架的很多排版和文字布局的功能。

在Adobe Labs你还可以查看APIs和针对Flash CS4,Flex 3.2和Gumbo的例子。

本页面已经被浏览12,591次。
CopyRight © 2007-2012 北京冠游时空数码技术有限公司, All Rights Reserved.
9RIA.com 天地会 京ICP备11007422号-2