[原文链接: http://guyinthechair.com/2010/06/the-flash-text-engine-part-2-interaction/ ]
[原文作者: Paul Taylor 原文时间: Jun. 28, 2010 ]
[原创翻译: http://www.smithfox.com/?e=183 ,转载请保留此声明, 谢谢]
这是介绍Flash文本引擎系列文章的第二部分: 第一部分, 第二部分, 第三部分.
首先需要澄清, 这些系列文章不是写Adobe的文本布局框架(Text Layout Framework, 以下简称TLF)的, TLF是一个高级的排版和文字布局框架, TLF是建立在FTE(Flash Text Engine)之上的, FTE是一个低层的Player native API, 它在flash.text.engine package内.
在前一篇文章中, 我介绍了如何渲染TextLine, 本文将介绍如何和已经创建的TextLine交互.
TextLine是一个InteractiveObjects对象, 你可以直接增加event listener以侦听哪些交互事件。
FTE也能让你为每一个ContentElement指定EventDispatcher. 当用户和ContentElement的数据交互时, 会clone到用户指定的EventDispatcher. 我在下面的讨论中, 你会发现每种方法都有其长处和短处.
因为TextLine是InteractiveObject, 你可以监听每个TextLine实例的键盘和鼠标事件. 这种方式, 你能知道是在和哪个TextLine在交互, 但主要缺点是对其所正在渲染的ContextElement却一无所知. 一个TextLine可以渲染多个ContentElement, 多个TextLine又可以渲染同一个ContentElement.
看下面的Demo:
Source
实际上, 有的情况, 你也没有必要知道是哪些ContentElement, 比如, 你不关心TextLine的修饰: 下划线, 删除线, 是否被选中.
下面的Demo是可以选择文字的:
Source
FTE交互的首选方式还是用 TextLineMirrorRegions, 上篇文章说过: 你必须用 TextElement, GraphicElement, or GroupElement 之一来创建文本实例. 创建后你可以设置ContentElement.eventMirror属性为你所指定的EventDispatcher. 这种方式能让你和特定的ContentElement交互.
在下面的demo代码中, 我创建了一个EventDispather对象, 并且设置给TextElement.eventMirror属性, 然后监听这个EventDispather对象的 mouseMove 事件, 每当Mouse over这个TextElement时, 就会trace下来.
var dispatcher:EventDispatcher = new EventDispatcher(); new TextElement('Inspiring quote here.', new ElementFormat( new FontDescription()), dispatcher); var onMouseMove:Function = function(e:MouseEvent):void{ trace('Mouse move on ' + e.target.toString()); } dispatcher.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
下面Demo中的两行文字是同一个TextElement的两个不同的部分:
Source
和之前的Demo有什么不同之处? TextLine有一个mirrorRegions 属性, 保存了TextLineMirrorRegion数组(Vector). 由于多个ContentElement能被同一个TextLine所渲染, TextLine会为每个ContentElement创建TLMR实例, 并且分别赋给各个ContentElement.eventMirror属性.
TextLine会监听自己的交互事件, 当事件和任何一个TLMR的事件重叠时, TextLine会通知相应的TLMR. 在所有TextLine的正常事件处理结束后. 每个TLMR会用其eventMirror属性所指的EventDispather实例再次dispatch事件一次.
这个例子中, 我为TextLine和其ContentElement的eventMirror都监听了 "MouseDown" 事件. 注意eventMirror的事件触发的时间:
Source
下面的Demo, 我用TextLineMirrorRegion为每个Element设置了不同的样式
Source
如果没有<注意事项>, 那就不是flash player的功能了 :)
TLMR只是模拟了事件, 它不会re-dispatch它从TextLine所接受到的实例, 因为TLMR不是一个InteractiveObject.
如果你用eventMirror来监听 MouseEvent, 你要意识到那是一个伪造的事件 -- 就算是target是TextLine, 也是这样,
这些事件不是源自TextLine, 这点和player原生的事件不一样.
这种模拟机制, 也意味着我们受到Adobe选择这样做的摆布(或是限制), 他们觉得没有必要模拟rollover/rollout事件. 你会发现eventMirror并没有roll相关的事件. 由于ContentElement并没有display-list children, roll event的行为就和mouseover, mouseout的行为完全一样, 相必Adobe是基于这一点认为没有必要实现roll事件的.
然而, Roll事件还是非常有必要的,
尽管 ContentElement没有 display-list children, 然而它还是有 ContentElement children的, 相当于 ContentElement的层次结构代替了 disply 的层次结构, 所以 roll 事件还是必须的.
举个例子, 看下面的xml model的渲染:
<p> Outside the group. <group> <text color="#44AA00"> First group child. </text> <text color="#AA0044"> Second group child. </text> </group> Outside the group. </p>
上面这种case, 你可能想让group这个node作为一个整体来看待, (就像一个带children的DisplayObjectContainer 那样).
下面就上这个xml model的例子, 你将鼠标在 First group child和 Second group child之间划动时, 你会发现你紧接着会看到来自group的 "mouseout", "mouseover"两个事件, 如果是roll 事件, 应该只会收到从child来的mouseover和mouseout, 应该没有group的相关mouseover和mouseout事件. 下面的这个demo, 按Mouse, 会清空 trace.
Source
那, 怎么搭配这两种方法呢? 简而言之, 就是: 看情况. 如果你只是需要基本的交互功能, 而并不关心上下文(比如 selection你就需要关心上下文), 那就直接在TextLine上加listener. 如果你需要关心上下文, 需要知道是在和哪个ContentElement交互, 那你只能选择 event mirroring 的方式.
也许我有点强迫症, 每次悬停在FTE文字上时, 我非常希望能看到 I 型的光标, 我最喜欢的Demo, 还是第二个, 因为我实现了 I 型的光标 :) , 总之, 希望你也喜欢! 祝你好运!