[原文链接: 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内.
FTE交互
在前一篇文章中, 我介绍了如何渲染TextLine, 本文将介绍如何和已经创建的TextLine交互.
TextLine是一个InteractiveObjects对象, 你可以直接增加event listener以侦听哪些交互事件。
FTE也能让你为每一个ContentElement指定EventDispatcher. 当用户和ContentElement的数据交互时, 会clone到用户指定的EventDispatcher. 我在下面的讨论中, 你会发现每种方法都有其长处和短处.
方法一: 将TextLine看作InteractiveObject
因为TextLine是InteractiveObject, 你可以监听每个TextLine实例的键盘和鼠标事件. 这种方式, 你能知道是在和哪个TextLine在交互, 但主要缺点是对其所正在渲染的ContextElement却一无所知. 一个TextLine可以渲染多个ContentElement, 多个TextLine又可以渲染同一个ContentElement.
看下面的Demo:
实际上, 有的情况, 你也没有必要知道是哪些ContentElement, 比如, 你不关心TextLine的修饰: 下划线, 删除线, 是否被选中.
下面的Demo是可以选择文字的:
方法二: 用TextLineMirrorRegions (以面简写成TLMRs)
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的两个不同的部分:
和之前的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的事件触发的时间:
下面的Demo, 我用TextLineMirrorRegion为每个Element设置了不同的样式
注意事项:
如果没有<注意事项>, 那就不是flash player的功能了 :)
TLMR只是模拟了事件, 它不会re-dispatch它从TextLine所接受到的实例, 因为TLMR不是一个InteractiveObject.
如果你用eventMirror来监听 MouseEvent, 你要意识到那是一个伪造的事件 -- 就算是target是TextLine, 也是这样,
这些事件不是源自TextLine, 这点和player原生的事件不一样.
Rollover/rollout事件
这种模拟机制, 也意味着我们受到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.
比较:
那, 怎么搭配这两种方法呢? 简而言之, 就是: 看情况. 如果你只是需要基本的交互功能, 而并不关心上下文(比如 selection你就需要关心上下文), 那就直接在TextLine上加listener. 如果你需要关心上下文, 需要知道是在和哪个ContentElement交互, 那你只能选择 event mirroring 的方式.
P.S.
也许我有点强迫症, 每次悬停在FTE文字上时, 我非常希望能看到 I 型的光标, 我最喜欢的Demo, 还是第二个, 因为我实现了 I 型的光标 :) , 总之, 希望你也喜欢! 祝你好运!