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


    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, 上篇文章说过: 你必须用  TextElementGraphicElement, 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 型的光标 :)  , 总之, 希望你也喜欢! 祝你好运!

  • 相关阅读:
    python读取csv数据(添加列名,指定分隔方式)
    loc_survived
    数据预处理
    hadoop 指令
    pd.concat
    DataFrame
    SQL左连接
    mysql mysql之把查询的结果保存到新表(小知识点)
    啦啦啦啦 mysql 授权
    ArrayList和LinkedList的区别以及优缺点
  • 原文地址:https://www.cnblogs.com/ddw1997/p/2861352.html
Copyright © 2020-2023  润新知