About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • Jan

    16

    Feathers3 Alert 一些备注

    • 0 Comments
    • Flash Platform

    Alert 组件实例的创建方式与创建其它组件有点不同,它不是通过调用构造函数来创建的,而是通过调用 Alert.show() 静态方法来创建的,这个方法第三个参数是一个 ListCollection 对象,定义一组按钮 ButtonGroup 对象与铵钮相关的事件回调函数:

    var alert:Alert = Alert.show( "I have something important to say""Warning"new ListCollection(
        [
            { label: "OK", triggered: okButton_triggeredHandler }
        ]) );

    除了能够侦听单个按钮的 Event.TRIGGERED 事件之外,还能侦听整个 Alert 对象的 Event.CLOSE 事件:

    alert.addEventListener( Event.CLOSE, alert_closeHandler );

    事件对象的 data 属性会包含(其实是引用吧)按钮组中与触发事件相关的按钮对象:

    function alert_closeHandler( event:Event, data:Object ):void
    {
        if( data.label == "OK" )
        {
            // the OK button was clicked
        }
    }

    icon 参数是可选的,它可以是任何 Starling 显示对象。

    isModal 参数是可选的,决定是否为模态窗口。

    Alert 显示的时候是通过 PopUpManager 的方法实现的。默认情况下,添加模态窗口时“叠加层(overlays)”的显示对象也是通过 PopUpManager 方法实现的,可以通过静态方法 overlayFactory() 来修改所有 Alert 的模态窗口叠加层。

    Alert.overlayFactory = function():DisplayObject
    {
        var tiledBackground:Image = new Image( texture );
        tiledBackground.tileGrid = new Rectangle();
        return tiledBackground;
    };

    这时调用 PopUpManager.addPopUp() 方法显示 alert 时,这个 overlayFactory() 生成的显示对象就有用了。

    isCentered 参数是可选的,决定 Alert 对象是否居中显示,设为 true 时如果窗口修改大小,它会重新居中。

    customAlertFactory 参数决定一个完全自定义的 Alert :

    function customAlertFactory():Alert
    {
        var alert:Alert = new Alert();
        alert.styleNameList.add( "custom-alert" );
        return alert;
    };
    Alert.show( "I have something important to say""Alert Title"new ListCollection({label: "OK"}), true, true, customAlertFactory );

    类似上面这段代码,可以通过主题文件(theme)来自定义这个名为 “custom-alert” 的 Alert 独特样式。

    可以通过如下代码来修改 alert 窗口中消息内容处的字体样式:

    alert.fontStyles = new TextFormat( "Helvetica"20, 0x3c3c3c );
    alert.disabledFontStyles = new TextFormat( "Helvetica"20, 0x9a9a9a );

    但如果要修改标题和按钮的样式需要先获取 header 与按钮组的引用,再修改。

    一般推荐使用通过主题文件(theme)来实现自定义样式。

    如果想程序化的移除 alert 对象,可以使用如下类似的代码:

    alert.removeFromParent( true );

    Jan

    12

    Robotlegs2 AS3 流程白话

    • 0 Comments
    • Flash Platform

    1、ContextView:给 ContextView 传入一个上下文背景对象,一般是 stage 或根容器(上下文背景是指发生的环境,Robotlegs 能起作用的范围)。

    2、Context 对象在 configure()  的时候会初始化;但在 Flex 框架中添加完配置后,它有可能不会自动执行初始化,需要编码执行以下代码:

    if(!context.initialized)
        context.initialize();

    3、Config 文件中可以配置 map 映射(Config 不一定需要实现 IConfig 的接口,但推荐实现),最常见的是注入以下三个对象:

    [Inject]
    public var injector:IInjector;

    [Inject]
    public var mediatorMap:IMediatorMap;

    [Inject]
    public var commandMap:IEventCommandMap;

    这里注入的意思是指当遇到 [Inject] 元标签时,会自动按变量名的类型生成一个对象(这个类型可以是接口类型,它会自动生成对应的实现类对象)赋值给这个变量名,开发者不需要手动去 new 一个对象出来然后赋值给变量名。

    一般的映配置是这样子的:

    a、一个 View 对象(比如一个操作面板) 对应一个 Mediator 对象,当 View 对象被添加到舞台的时候,Mediator 对象会自动生成。

    b、一个 Event 事件对象对应一个 Command 命令,当事件发生的时候,会自动执行 Command 中的 execute() 方法。

    c、一个 Model 被映射成单例,injector.map(SomeModel).asSingleton(); 

    一篇 Robotlegs1 的资料《ROBOTLEGS轻量级AS3框架》,虽然不是 Robotlegs2 的资料,但它里面的流程(数字1、2、3、4……)其实一样,很清晰了: 

    图中 Context 对象里面有一个“事件公车”,其实就是一个 EventDispatcher 对象它既能派发事件,又能侦听事件。

    More...

    Jan

    12

    偶然看到 .Net库:SwfDotNet ,可以用于动态生成 swf 文件,可能对于搞服务器开发的人有用(个人感觉可能它还不如 SWFTools、haxe、neko、swfmill 等一些小型工具好使,如果是大型的 Flash 应用或游戏开发,估计是完全派不上什么用处)。

    Jan

    11

    以下测试环境为 Starling 2.1 与 Feathers UI 3.1.1

    package
    {
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;

        import starling.core.Starling;

        public class Starling2Test extends Sprite
        {
            private var _starling:Starling;

            public function Starling2Test()
            {
                super();

                stage.align = StageAlign.TOP_LEFT;
                stage.scaleMode = StageScaleMode.NO_SCALE;

                _starling = new Starling(Starling2, stage);
                _starling.start();

                _starling.skipUnchangedFrames = true;//默认为 false,设为 true

                _starling.showStatsAt();//新版的概要分析器在上面的属性为true时如果跳过了场景的重绘时背景会变绿色
            }
        }
    }

    接下来看看概要分析器的背景会不会变绿色。

    1、先来个空场景,没有任何重绘,这个很正常。 

    package
    {
        import starling.display.Sprite;

        public class Starling2 extends Sprite
        {
            public function Starling2()
            {
                super();//空场景,概要分析器变绿色了
            }
        }
    }

    2、往原生舞台添加一个空白容器对象:

    package
    {
        import flash.display.Sprite;

        import starling.core.Starling;
        import starling.display.Sprite;

        public class Starling2 extends starling.display.Sprite
        {
            private var sp:flash.display.Sprite = new flash.display.Sprite();

            public function Starling2()
            {
                super();

                //往原生舞台添加一个空的 Sprite 对象,依旧可以跳过帧重绘,背景变绿
                Starling.current.nativeOverlay.addChild(sp);
            }        
        }    
    }

    这时候你可能会觉只要原生舞台没有对象绘制,skipUnchangedFrames 依旧会起作用,可以跳过静态的帧画面重绘,实际上是错的……看下面:

    package
    {
        import flash.display.Shape;

        import starling.core.Starling;
        import starling.display.Sprite;

        public class Starling2 extends starling.display.Sprite
        {
            private var shape:Shape = new Shape();

            public function Starling2()
            {
                super();

                //往原生舞台添加一个空 Shape 对象,无法跳过帧重绘,概要分析背景一直是黑色的
                Starling.current.nativeOverlay.addChild(shape);
            }        
        }    
    }

    3、回到刚才的 Sprite 对象,给它加点需要原生舞台绘制的东西试试:

    package
    {
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.display.Sprite;

        import starling.core.Starling;
        import starling.display.Sprite;

        public class Starling2 extends starling.display.Sprite
        {
            private var sp:flash.display.Sprite = new flash.display.Sprite();

            private var bit:Bitmap = new Bitmap(new BitmapData(5050, false, 0xff0000));

            public function Starling2()
            {
                super();

                Starling.current.nativeOverlay.addChild(sp);

                sp.graphics.beginFill(0xff);
                sp.graphics.drawRect(0,0,100,100);
                sp.graphics.endFill();

                sp.y = 200;

                //如果没有将 Bitmap 对象加到显示列表中,它依旧是可以变绿的
                //如果将以下 bit 对象加到显示列表中,skipUnchangedFrames 就失效了,不能跳过任何帧,背景依旧是黑色的
                //sp.addChild(bit);
            }        
        }    
    }

    实际测试结果,不仅是 Bitmap 会让 skipUnchangedFrames 失效,原生的 TextField 对象也会让 skipUnchangedFrames 失效。只要不往原生舞台添加任何对象就可以了吧?但有时候你可能是被迫的,甚至是你完全不知情的情况下往原生舞台添加了显示对象。举两个常见例子:

    a、如果需要一个动态文本框用于输入用户帐号和密码、对话框等,那么你就不得不往原生舞台添加传统的 TextField 对象;

    b、当使用 feathers 组件的 TextInput 组件时,你没有往原生舞台添加任何对象,但实际上 feathers 组件会自动往原生舞台添加动态文本框的过程,你完全可能就是在不知情的情况下被添加了。

    当 TextInput 获取了焦点有了输入光标时,实际上有一个输入文本框被 feathers 自动添加到了原生舞台。

    4、上面这些其实还不够精彩,重头戏来了。颤抖吧,骚年!

    package
    {
        import starling.display.Quad;
        import starling.display.Sprite;
        import starling.events.Event;

        public class Starling2 extends Sprite
        {        
            private var q:Quad = new Quad(10,10,0xffff);

            public function Starling2()
            {
                super();

                this.addChild(q);
                this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            }

            private function enterFrameHandler(e:Event):void
            {
                q.y = 200;
                q.y = 100;
                q.y = 200;            
            }
        }
    }

    你会发现运行上面的代码后,概要分析器的背景颜色并没有变成绿色,尽管帮助手册上 skipUnchangedFrames 的说明写了:

    When enabled, Starling will skip rendering the stage if it hasn't changed since the last frame.

    大概意思是:只要舞台上的对象前一帧和后一帧如果都没有发生任何变化,Starling 会跳过重绘。

    所以这个属性实际上并不会像 feathers 框架那样有一个 flag 标记通过 invalidate() 方法验证前一帧与后一帧是否真正的变化过(和 Flex 框架里的组件类似),如果是 feathers :

    package
    {
        import feathers.controls.Label;

        import starling.display.Sprite;
        import starling.events.Event;

        public class Starling2 extends Sprite
        {
            private var label:Label = new Label();

            public function Starling2()
            {
                super();            

                this.addChild(label);

                label.y = 200;
                label.text = "aaaaaaaaaaa";

                this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);            
            }

            private function enterFrameHandler(e:Event):void
            {
                /*
                //这一段代码需要注释掉,否则概要分析器的背景也不会变绿
                //因为 feathers 组件并没有对 x 与 y 进行 flag 标记
                label.y = 200;
                label.y = 100;
                label.y = 200;
                */


                //概要分析器背景是绿色的。
                //但它真的利用了 skipUnchangedFrames 属性的功能了吗?
                label.width = 200;
                label.width = 100;
                label.width = 200;

                label.text = "aaaaaaaaaaa";
                label.text = "bbbbbbbbbbb";
                label.text = "aaaaaaaaaaa";            
            }        
        }    
    }

    feathers 阻止重绘是通过 flag 标记与 invalidate() 方法验证实现的,和 skipUnchangedFrames 属性有半毛钱关系?我整个人都不好了。

    Jan

    11

    Starling 移除方法中 dispose 的功能:移除对象的同时会移除它的全部侦听器、以及移除子级对象的全部侦听器,释放对象与子对象的所有 GPU 显存。

    package
    {
        import starling.display.Quad;
        import starling.display.Sprite;
        import starling.events.Event;
        import starling.events.TouchEvent;

        public class Game extends Sprite
        {
            private var sp:Sprite = new Sprite();

            private var sub1:Sprite = new Sprite();
            private var sub2:Sprite = new Sprite();

            private var sub1sub:Sprite = new Sprite();

            public function Game()
            {
                super();

                this.addChild(sp);

                sp.addChild(sub1);
                sp.addChild(sub2);

                sub1.addChild(sub1sub);

                sp.addEventListener(TouchEvent.TOUCH, touchHandler);

                sub1.addEventListener(TouchEvent.TOUCH, touchHandler);
                sub2.addEventListener(TouchEvent.TOUCH, touchHandler);

                sub1sub.addEventListener(TouchEvent.TOUCH, touchHandler);
                sub1sub.addEventListener(Event.ENTER_FRAME, enterFrameHandler);

                trace(sp.hasEventListener(TouchEvent.TOUCH));//true
                trace(sub1.hasEventListener(TouchEvent.TOUCH));//true
                trace(sub2.hasEventListener(TouchEvent.TOUCH));//true
                trace(sub1sub.hasEventListener(TouchEvent.TOUCH));//true
                trace(sub1sub.hasEventListener(Event.ENTER_FRAME));//true

                trace("========================");

                sub1.addChild(new Quad(100,100,0xff));//这个 Quad 显示对象会在以下方法被调用时被销毁
                sub1.removeFromParent(true);//一个对象从父级移除时设置 dispose 参数为 true

                sp.addChild(sub1);

                trace(sp.hasEventListener(TouchEvent.TOUCH));//true
                trace(sub1.hasEventListener(TouchEvent.TOUCH));//false
                trace(sub2.hasEventListener(TouchEvent.TOUCH));//true
                trace(sub1sub.hasEventListener(TouchEvent.TOUCH));//false
                trace(sub1sub.hasEventListener(Event.ENTER_FRAME));//false

                sp.removeChild(sub1sub);//这个比较奇葩,如果被移除的对象不是父级的子对象,它也不会抛出异常
            }

            private function enterFrameHandler(e:Event):void
            {
            }

            private function touchHandler(e:TouchEvent):void
            {
            }

        }

    }

    注意:上面的 Quad 对象的显存被释放掉了;另一个奇葩现象是一个容器在移除另一个对象时,即使不是“父子”关系(而是“子父”关系)、或两对象没有任何“父”与“子”关系,它也不会像原生 API 那样抛出异常。

    Jan

    8

    Feathers SDK 的安装与使用

    • 0 Comments
    • Flash Platform

    Feathers SDK, 喜欢利用 MXML 语言进行界面布局的可以试试(估计用过 Flex 的都会喜欢)。比较简单的方式,是通过 Feathers SDK Manager 这个工具来安装 Feathers SDK 的安装与使用(也可以直接下载 SDK 二进制包 “SDK Binary Packages”,然后通过手动方式安装,涉及到命令行操作,复杂一些)。

    需要注意的是:Feathers SDK Manager 这个工具在自动下载与安装时,可能会失败并产生以下报错:

    [get] [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2032" errorID=2032]

    这是下载时线路问题或Adobe的服务器问题,我试了移动宽带安装失败,连接电信宽带可以成功;在另一台计算机上因为没有电信宽带,尝试了代理服务器,走日本线路失败,走荷兰的线路成功了。所以安装失败的时候可以试试换一下宽带服务商或换一下代理服务器。

    安装好了 Feathers SDK 后,需要将它与 Flash Builder 整合起来(也可以与 IntelliJ IDEA 整合起来,没用过,反正我只喜欢  Flash Builder):

    1、因为要修改 Flash Builder 配置与模板,所以需要切换到一个新的工作空间。

    2、在 Flash Builder 的“首先项 / 偏好设置”中设置“Flash Builder ——已安装的 Flex SDK” 添加 Feathers SDK 目录并勾选,再点击“应用”。

    3、下载 Feathers SDK 模板文件,在“首先项 / 偏好设置”中设置“Flash Builder ——文件模板” ,导入下载好的模板文件,再点击“应用”与“确定”。

    4、在创建项目的时候,选择“Flex 手机项目”或“Flex 项目”就可以了。

    Feathers SDK 与 MXML 的简单入门介绍:《Getting started with MXML in the Feathers SDK》。

    Feathers SDK 与 MXML 的详细完整介绍:《The complete guide to MXML in the Feathers SDK》。

    Jan

    5

    Starling2 和第一个版本一样,依旧没有提供全局的帧频设置,依旧是通过原生舞台的帧频控制 Starling 的全局帧频。

    Starling.current.nativeStage.frameRate = 60;

    Jan

    5

    和 Starling旧版一样,2.0的版本设置步骤仍然是异步的,也就是如下步骤产生 Game 类的实例并不是同步的,不能直接调用 Game 类实例中的方法:

    package
    {
        import flash.display.Sprite;
        import starling.core.Starling;

        [SWF(width="640", height="480",
             backgroundColor="#808080",
             frameRate="60")]
        public class Main extends Sprite
        {
            private var _starling:Starling;

            public function Main()
            {
                _starling = new Starling(Game, stage);
                _starling.start();
            }
        }
    }

    但可以侦听 ROOT_CREATED 事件:

    public function Main()
    {
        _starling = new Starling(Game, stage);
        _starling.addEventListener(Event.ROOT_CREATED, onRootCreated);
        _starling.start();
    }

    private function onRootCreated(event:Event, root:Game):void
    {
        root.start()// 'start' needs to be defined in the 'Game' class
    }

    Dec

    27

    AS3 的一些“奇葩”资料

    • 0 Comments
    • Flash Platform

    1、switch 的 default 关键字通常出现在最后,或者可以被省略,但它却可以合法的出现在 switch 语句的任何地方。

    2、switch 的条件表达式与 case 表达式比较的时候,使用的是“===”,而不是“==”。

    3、Flex 和 MXML 中,程序的主类必须放在匿名包中。

    4、使用数组索引访问数组时,如果索引值大于数组的长度,返回undefined,但数组的长度本身并不产生变化。

    5、get 方法会在 set 方法后自动被调用,所以 get 方法里的变量如果用于计数,会被 set 方法搅乱。

    6、函数内的代码如果放在嵌套函数中,在 return 后是可以继续执行的,函数会自动向前引用。

    7、AVM 加载类的时候才执行类初始化程序(静态初始化/静态块)。

    8、即使在严格模式下,以下三种情况也会忽略类型不匹配错误:

    a、无类型表达式赋值给类型表达式。

    b、任何表达式赋值给 Boolean 类型。

    c、任何数值类型实例被用于希望得到不同的数值类型实列。

    9、实例转换类型包含转型,但实例“转型”不同于“转换”类型(这是在玩文字游戏么……听起来好搞):

    A、类型(表达式),这种是转换。

    a、转换成功返回表达式。

    b、转换失败会有两种结果:如果是原生类型,会被强制转换;如果是非原生类型,产生运行时异常。

    B、表达式 as 类型,这种是转型(不是转换)。

    a、转型成功返回表达式。

    b、转型失败返回 null(就算是转型到原生类型失败也只返回 null 值)。

    10、throw 作为编程惯例只抛出 Error 类或它的子类,但实际上它能抛出任意数据类型。

    11、finally 块中的代码一定会被执行,包括在return/continue/break等语句转出时;而且优先执行于外部冒泡捕获异常时的代码。

    12、一个动态类的子类不被当作是动态的,除非子类也包含 dynamic 修饰。

    13、所有动态实例变量都是无类型且公有的(动态实例变量的性能相较于正规的实例变量的性能低一些)。

    14、标识符的规则不适用于中括号“[]”运行符创建的变量。如 obj["111"]这种纯数字标识符也是合法的。

    15、AS3 依旧支持使用 prototype 增强类。

    16、开放的命名集甚至优先于 use namespace 语句的使用(就好像  use namespace 被自动移动到了一个作用域代码块的顶部)。

    17、开放的命名空间对嵌套作用域保持开放。

    18、一个命名空间一旦被开放,就不能被“关闭”,也不能被移除。

    19、使用通配符 * 导入一个包的时候,只是导入了包的 public 命名空间,并没有开放 internal 命名空间。

    20、E4X 分析器默认忽略 XML 注释与处理指令。

    21、当parent()被调用于表示 XML 实例的一个属性时,它返回属性被定义的那个元素。

    22、XML 是动态类,AS推迟类型检查直到运行时。

    23、AS3.0 实现的 E4X 规定引用不存在的 XML 属性时返回一个空的 XMLList 对象,不会产生异常。

    24、XML 的方法有可能会被“转发”XMLList,但并不涉及类型“转换”,所以当需要类型检验时,一个 XMLList 并不能自动转换成 XML 类型,需要显示引用 XML 实例。

    25、XMLList 中的 XML 元素名并非变量名,使用 for - in 可以遍历出它们的变量名为“0、1、2……”

    26、谓词过滤之前可以先使用 hasOwnPropety() 来检查属性或元素是否存在。

    27、如果在加载策略文件之后立即调用加载数据的命令,FlashPlayer 会在加载数据之前自动等待策略文件的加载。

    28、注册在事件目标阶段的侦听器,如果 usecapture 被设置为 true,就永远不会被触发了。

    29、关于事件流在传播过程中的奇葩情况老贴《AS3事件流机制中二个重要的应用知识

    30、当一个输入法 IME 在使用的时候,键盘事件相关的实例变量keyCode和charCode是不被支持的。

    31、如果通过 TimerEvent.TIMER 事件来更新屏幕,最多可以产生十次(10倍于帧速)。

    32、调用 Graphics 实例的 clean() 方法后,对象的线型会被还原成为 undefined,画笔位置还原为 0,0。

    33、和 appendText 不同,“+=”运算符将文本域中的所有文本格式重置为默认文本格式;并且“+=”的性能也低。

    34、即使被 FlashPlayer 打开的第一个 SWF 文件从舞台上被移除,它仍然被当作舞台拥有者,并且控制相对URL 解析。

    35、使用 Socket 类和 Loader 类的 loadBytes()方法结合使用,可以防止被加载的资源出现在缓冲区(如WIN 系统的IE临时文件夹)。

    36、对于模运算符,如果运算的对象不是整数,可能会出现一些意外的小数。

    37、in 运算符可以用来判断一个对象是否作为另一个对象的键或索引,存在返回 true,否则就是 false。

    38、函数如果使用了...(rest)关键字,那么 arguments 就不能再使用了。

    39、函数语句定义法定义的函数本质:MethodClosure 类不是动态类;函数直接量表达式定义的函数本质:Function-N 是动态类。

    Dec

    9

    《大话西游2》插曲《一生所爱》简谱

    More...