您的位置:首页 > 其它

[转] Flash文本引擎, 第二部分: 交互

2013-01-15 15:55 417 查看

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:

package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.engine.*;
import flash.utils.Dictionary;

[SWF(width="235", height="100")]
public class SimpleDemo2 extends Sprite
{
public function SimpleDemo2()
{
super();

setup();
}

private var lineNumbers:Dictionary = new Dictionary(false);

private function setup():void
{
addChild(lineHolder);
lineHolder.y = 40;
lineHolder.x = 130;

var elements:Vector.<ContentElement> = new Vector.<ContentElement>();
elements.push(
createTextElement('Be careless ', 26),
createTextElement('in your dress if you will, ', 16),
createTextElement('but keep a ', 20),
createTextElement('tidy soul.', 26),
createTextElement('\n - Mark Twain', 20)
);

var i:int = 0;
var block:TextBlock = new TextBlock(new GroupElement(elements));
var line:TextLine = block.createTextLine(null, 125);
var _y:Number = 0;
while(line)
{
addChild(line);

_y += line.height;

line.y = _y;

line.addEventListener(MouseEvent.ROLL_OVER, onMouseEvent);
line.addEventListener(MouseEvent.ROLL_OUT, onMouseEvent);
line.addEventListener(MouseEvent.CLICK, onMouseEvent);
line.addEventListener(MouseEvent.MOUSE_DOWN, onMouseEvent);
line.addEventListener(MouseEvent.MOUSE_UP, onMouseEvent);

lineNumbers[line] = ++i;

line = block.createTextLine(line, 125);
}
}

private function createTextElement(text:String, size:int):TextElement
{
return new TextElement(text, new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
size)
);
}

private function onMouseEvent(event:MouseEvent):void
{
var target:TextLine = TextLine(event.target);

renderNotification(lineNumbers[target] + ': ' + event.type);
}

private var lineHolder:Sprite = new Sprite();

private function renderNotification(text:String):void
{
while(lineHolder.numChildren)
lineHolder.removeChildAt(0);

var block:TextBlock = new TextBlock(
new TextElement(text,
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
18)
)
);
var line:TextLine = block.createTextLine(null, 200);
while(line)
{
lineHolder.addChild(line);

line.y = line.height;

line = block.createTextLine(line, 200);
}
}

[Embed(source="assets/Times New Roman.ttf", embedAsCFF="true", fontFamily="Times")]
private var times:Class;
}
}


实际上, 有的情况, 你也没有必要知道是哪些ContentElement, 比如, 你不关心TextLine的修饰: 下划线, 删除线, 是否被选中.

下面的Demo是可以选择文字的:

package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.engine.*;
import flash.ui.Mouse;
import flash.ui.MouseCursor;

[SWF(width="400", height="125")]
public class FTEDemo7 extends Sprite
{
private var beginIndex:int = -1;
private var endIndex:int = -1;
private var lines:Array = [];

public function FTEDemo7()
{
var elements:Vector.<ContentElement> = new Vector.<ContentElement>();
elements.push(
createTextElement('He ', 20),
createTextElement('who loves ', 16),
createTextElement('practice ', 26),
createTextElement('without ', 16),
createTextElement('theory ', 26),
createTextElement('is like the ', 16),
createTextElement('sailor ', 20),
createTextElement('who boards his ship without a ', 16),
createTextElement('rudder ', 26),
createTextElement('and ', 16),
createTextElement('compass ', 26),
createTextElement('and ', 16),
createTextElement('never knows where he may cast.', 24),
createTextElement('\n - Leonardo da Vinci', 22)
);

var i:int = 0;
var block:TextBlock = new TextBlock(new GroupElement(elements));
var line:TextLine = block.createTextLine(null, 400);
var _y:Number = 0;
while(line)
{
lines.push(addChild(line));
_y += line.height;
line.y = _y;
line.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
line.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
line.addEventListener(MouseEvent.ROLL_OVER, onRoll);
line.addEventListener(MouseEvent.ROLL_OUT, onRoll);
line = block.createTextLine(line, 400);
}
}

private function createTextElement(text:String, size:int):TextElement
{
return new TextElement(text, new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
size)
);
}

private function onMouseDown(event:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
graphics.clear();
var line:TextLine = TextLine(event.target);
beginIndex = line.textBlockBeginIndex + line.getAtomIndexAtPoint(event.stageX, event.stageY);
}

private function onMouseMove(event:MouseEvent):void
{
if(!event.buttonDown)
return;

var line:TextLine = TextLine(event.target);
endIndex = line.textBlockBeginIndex + line.getAtomIndexAtPoint(event.stageX, event.stageY);
drawBackground(beginIndex, endIndex);
}

private function onMouseUp(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);

var objs:Array = getObjectsUnderPoint(new Point(event.stageX, event.stageY));
var obj:Object;
var found:Boolean = false;
while(objs.length)
{
if(objs.pop() is TextLine)
{
found = true;
break;
}
}

Mouse.cursor = found ? MouseCursor.IBEAM : MouseCursor.ARROW;
}

private function drawBackground(begin:int, end:int):void
{
graphics.clear();

if(begin > end)
{
var begin2:int = begin;
begin = end;
end = begin2;
}

var line:TextLine;
for(var i:int = 0; i < lines.length; i++)
{
line = lines[i];
if(line.textBlockBeginIndex <= begin && (line.textBlockBeginIndex + line.rawTextLength) >= begin)
break;
}

var startLine:TextLine = line;

for(i = 0; i < lines.length; i++)
{
line = lines[i];
if(line.textBlockBeginIndex <= end && (line.textBlockBeginIndex + line.rawTextLength) >= end)
break;
}

var endLine:TextLine = line;
line = startLine;
var bounds:Rectangle;

// Don't ever do this!
// I'm only doing this because I don't want errors
// and I didn't have time to vet this math 100%.
try
{
while(true)
{
if(line == null)
break;

if(line == startLine)
{
if(startLine == endLine)
bounds = line.getAtomBounds(Math.min(Math.max(begin - line.textBlockBeginIndex, 0), line.rawTextLength - 1)).union(line.getAtomBounds(Math.min(Math.max(end - line.textBlockBeginIndex, 0), line.rawTextLength - 1)));
else
bounds = line.getAtomBounds(Math.min(Math.max(begin - line.textBlockBeginIndex, 0), line.rawTextLength - 1)).union(line.getAtomBounds(line.rawTextLength - 1));
bounds.x += line.x;
bounds.y += line.y;
}
else if(line == endLine)
{
bounds = line.getAtomBounds(Math.min(Math.max(end - line.textBlockBeginIndex, 0), line.rawTextLength - 1)).union(line.getAtomBounds(0));
bounds.x += line.x;
bounds.y += line.y;
}
else
bounds = line.getBounds(line.parent);

graphics.beginFill(0x003399, 0.25);
graphics.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);

if(line == endLine)
break;

line = line.nextLine;
}
}
catch(e:Error)
{
// Do noooothing
}
}

private function onRoll(event:MouseEvent):void
{
Mouse.cursor = (event.type == MouseEvent.ROLL_OVER || event.buttonDown) ? MouseCursor.IBEAM : MouseCursor.ARROW;
}

[Embed(source="assets/Times New Roman.ttf", embedAsCFF="true", fontFamily="Times")]
private var times:Class;
}
}


方法二: 用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的两个不同的部分:

package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.text.engine.*;

[SWF(width="190", height="40")]
public class SimpleDemo3 extends Sprite
{
public function SimpleDemo3()
{
super();

addChild(lineHolder);
lineHolder.x = 100;

var dispatcher:EventDispatcher = new EventDispatcher();
dispatcher.addEventListener(MouseEvent.MOUSE_MOVE, onMouseEvent);
dispatcher.addEventListener(MouseEvent.MOUSE_OUT, onMouseEvent);
dispatcher.addEventListener(MouseEvent.MOUSE_OVER, onMouseEvent);
dispatcher.addEventListener(MouseEvent.MOUSE_DOWN, onMouseEvent);
dispatcher.addEventListener(MouseEvent.MOUSE_UP, onMouseEvent);
dispatcher.addEventListener(MouseEvent.CLICK, onMouseEvent);

var block:TextBlock = new TextBlock(new TextElement('The quick brown fox...',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
18),
dispatcher));
var line:TextLine = block.createTextLine(null, 100);
var _y:Number = 0;
while(line)
{
addChild(line);
_y += line.height;
line.y = _y;
line = block.createTextLine(line, 100);
}
}

private function onMouseEvent(event:MouseEvent):void
{
var target:TextLine = TextLine(event.target);

renderNotification(event.type);
}

private var lineHolder:Sprite = new Sprite();

private function renderNotification(text:String):void
{
while(lineHolder.numChildren)
lineHolder.removeChildAt(0);

var block:TextBlock = new TextBlock(
new TextElement(text,
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
18)
)
);
var line:TextLine = block.createTextLine(null, 200);
while(line)
{
lineHolder.addChild(line);

line.y = line.height;

line = block.createTextLine(line, 200);
}
}

[Embed(source="assets/Times New Roman.ttf", embedAsCFF="true", fontFamily="Times")]
private var times:Class;
}
}


和之前的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的事件触发的时间:

package
{
import flash.display.Sprite;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.text.engine.*;
import flash.utils.getTimer;

[SWF(width="285", height="55")]
public class SimpleDemo4 extends Sprite
{
public function SimpleDemo4()
{
addChild(lineHolder);
lineHolder.x = 80;
lineHolder.y = 5;
addChild(lineHolder2);
lineHolder2.x = 80;
lineHolder2.y = 25;

var dispatcher:EventDispatcher = new EventDispatcher();
dispatcher.addEventListener(MouseEvent.MOUSE_DOWN, onMouseMirrorEvent);

var block:TextBlock = new TextBlock(new TextElement('Click Me.',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
18),
dispatcher));
var line:TextLine = block.createTextLine(null, 75);
var _y:Number = 0;
while(line)
{
addChild(line);
_y += line.height;
line.y = _y;

line.addEventListener(MouseEvent.MOUSE_DOWN, onMouseLineEvent);

line = block.createTextLine(line, 75);
}
}

private var lineHolder:Sprite = new Sprite();
private var lineTime:Number = 0;
private function onMouseLineEvent(event:MouseEvent):void
{
lineTime = getTimer();

var block:TextBlock = new TextBlock(
new TextElement(event.type + ' from line',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
14)
)
);

while(lineHolder.numChildren)
lineHolder.removeChildAt(0);

var line:TextLine = block.createTextLine(null, 200);
var _y:Number = 0;

while(line)
{
lineHolder.addChild(line);

_y += line.height;

line.y = _y;

line = block.createTextLine(line, 200);
}
}

private var lineHolder2:Sprite = new Sprite();

private function onMouseMirrorEvent(event:MouseEvent):void
{
var block:TextBlock = new TextBlock(
new TextElement(event.type + ' from mirror, time between dispatches: ' + (getTimer() - lineTime) + 'ms',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
14)
)
);

while(lineHolder2.numChildren)
lineHolder2.removeChildAt(0);

var line:TextLine = block.createTextLine(null, 200);
var _y:Number = 0;

while(line)
{
lineHolder2.addChild(line);

_y += line.height;

line.y = _y;

line = block.createTextLine(line, 200);
}
}

[Embed(source="assets/Times New Roman.ttf", embedAsCFF="true", fontFamily="Times")]
private var times:Class;
}
}


下面的Demo, 我用TextLineMirrorRegion为每个Element设置了不同的样式

package
{
import flash.display.Sprite;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.text.engine.*;
import flash.utils.Dictionary;

[SWF(width="250", height="110")]
public class FTEDemo5 extends Sprite
{
public function FTEDemo5()
{
super();

// Only two things are infinite, the universe and human stupidity, and I'm not sure about the former. -Albert Einstein

var e1:TextElement = new TextElement('"Only ',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
16));
var e2:TextElement = new TextElement('two things',
new ElementFormat(
new FontDescription("Times", FontWeight.BOLD, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
24), new EventDispatcher());
var e3:TextElement = new TextElement(' are infinite, ',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
16));
var e4:TextElement = new TextElement('the universe',
new ElementFormat(
new FontDescription("Times", FontWeight.BOLD, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
26));
var e5:TextElement = new TextElement(' and ',
new ElementFormat(
new FontDescription("Times", FontWeight.BOLD, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
16));
var e6:TextElement = new TextElement('human stupidity',
new ElementFormat(
new FontDescription("Times", FontWeight.BOLD, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
26));
var e7:TextElement = new TextElement(', and ',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
16));
var e8:TextElement = new TextElement('I\'m not sure about the former.',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.ITALIC, FontLookup.EMBEDDED_CFF),
26), new EventDispatcher());
var e9:TextElement = new TextElement('" -',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.ITALIC, FontLookup.EMBEDDED_CFF),
16));
var e10:TextElement = new TextElement('Albert Einstein',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.ITALIC, FontLookup.EMBEDDED_CFF),
16), new EventDispatcher());

var colors:Array = [0x00FF00, 0xFF6600, 0x0066FF];
var mirrors:Dictionary = new Dictionary();
var color:uint;
var regions:Vector.<TextLineMirrorRegion>;
var region:TextLineMirrorRegion;
var bounds:Rectangle;

var vec:Vector.<ContentElement> = new Vector.<ContentElement>();
vec.push(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
var block:TextBlock = new TextBlock(new GroupElement(vec));
var line:TextLine = block.createTextLine(null, 250);
var _y:Number = 0;

while(line)
{
addChild(line);

_y += line.height;

line.y = _y;
regions = line.mirrorRegions;
while(regions && regions.length)
{
region = regions.pop();
if(region.mirror in mirrors)
color = mirrors[region.mirror];
else
color = colors.pop();

mirrors[region.mirror] = color;

bounds = region.bounds;
graphics.beginFill(color, 0.3);
graphics.drawRect(bounds.x, bounds.y + line.y, bounds.width, bounds.height);
}

line = block.createTextLine(line, 250);
}
}

[Embed(source="assets/Times New Roman.ttf", embedAsCFF="true", fontFamily="Times")]
private var times:Class;
}
}


注意事项:

如果没有<注意事项>, 那就不是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.

package
{
import flash.display.*;
import flash.events.*;
import flash.geom.Rectangle;
import flash.text.engine.*;
import flash.utils.Dictionary;

import flashx.textLayout.formats.BaselineOffset;

[SWF(width="400", height="110")]
public class FTEDemo6 extends Sprite
{
public function FTEDemo6()
{
var e1:TextElement = new TextElement('Outside the group. ',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
18));

var d2:EventDispatcher = new EventDispatcher();
d2.addEventListener(MouseEvent.MOUSE_OVER, function(e:Event):void{print("1: " + e.type);});
d2.addEventListener(MouseEvent.MOUSE_OUT, function(e:Event):void{print("1: " + e.type);});
var e2:TextElement = new TextElement('First group child. ',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
18, 0x44AA00), d2);

var d3:EventDispatcher = new EventDispatcher();
d3.addEventListener(MouseEvent.MOUSE_OVER, function(e:Event):void{print("2: " + e.type);});
d3.addEventListener(MouseEvent.MOUSE_OUT, function(e:Event):void{print("2: " + e.type);});
var e3:TextElement = new TextElement('Second group child. ',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
18, 0xAA0044), d3);

var e4:TextElement = new TextElement('Outside the group.',
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
18));

var vec:Vector.<ContentElement> = new Vector.<ContentElement>();
vec.push(e2, e3);

var groupDispatcher:EventDispatcher = new EventDispatcher();
groupDispatcher.addEventListener(MouseEvent.MOUSE_OVER, function(e:Event):void{print("group: " + e.type);});
groupDispatcher.addEventListener(MouseEvent.MOUSE_OUT, function(e:Event):void{print("group: " + e.type);});
var group:GroupElement = new GroupElement(vec, null, groupDispatcher);

var vec2:Vector.<ContentElement> = new Vector.<ContentElement>();
vec2.push(e1, group, e4);
var block:TextBlock = new TextBlock(new GroupElement(vec2));
var line:TextLine = block.createTextLine(null, 200);
var _y:Number = 0;

while(line)
{
addChild(line);
_y += line.height;
line.y = _y;

line = block.createTextLine(line, 200);
}

addChild(lineHolder);
lineHolder.x = 200;

addEventListener(MouseEvent.MOUSE_DOWN, clearLines);
}

private function clearLines(event:MouseEvent):void
{
while(lineHolder.numChildren)
lineHolder.removeChildAt(0);
}

private var lineHolder:Sprite = new Sprite();

private function print(str:String):void
{
while(lineHolder.numChildren > 6)
lineHolder.removeChildAt(0);

var block:TextBlock = new TextBlock(
new TextElement(str,
new ElementFormat(
new FontDescription("Times", FontWeight.NORMAL, FontPosture.NORMAL, FontLookup.EMBEDDED_CFF),
16)
)
);
var line:TextLine = block.createTextLine(null, 200);
while(line)
{
lineHolder.addChild(line);
line = block.createTextLine(line, 200);
}

var child:DisplayObject;
for(var i:int = 0; i < lineHolder.numChildren; i++)
{
child = lineHolder.getChildAt(i);
child.y = (i+1) * child.height;
}
}

[Embed(source="assets/Times New Roman.ttf", embedAsCFF="true", fontFamily="Times")]
private var times:Class;
}
}


比较:

那, 怎么搭配这两种方法呢? 简而言之, 就是: 看情况. 如果你只是需要基本的交互功能, 而并不关心上下文(比如 selection你就需要关心上下文), 那就直接在TextLine上加listener. 如果你需要关心上下文, 需要知道是在和哪个ContentElement交互, 那你只能选择 event mirroring 的方式.

P.S.

也许我有点强迫症, 每次悬停在FTE文字上时, 我非常希望能看到 I 型的光标, 我最喜欢的Demo, 还是第二个, 因为我实现了 I 型的光标 :) , 总之, 希望你也喜欢! 祝你好运!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: