About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • Jan

    17

    Feathers3 AnchorLayout 一些备注

    • 0 Comments
    • Flash Platform

    AnchorLayout 锚布局对象一般用在普通的 Feathers 容器控件对象中定位子对象的,一般如果带有数据提供者(data providers)、自带自动布局 layouts 的不会去用它,比如 List,GroupedList 这些组件不会用这种锚布局。

    锚布局同时支持尺寸与位置的布置,它比较好用的一个属性是 bottomAnchorDisplayObject,子对象如果是兄弟关系就可以进行相对定位,如:

    var button2:Button = new Button();
    button2.label = "Another Button";
    container.addChild( button2 );

    var layoutData2:AnchorLayoutData = new AnchorLayoutData();
    layoutData2.right = 10;
    layoutData2.bottom = 10;
    layoutData2.bottomAnchorDisplayObject = button1;//相对于 button1 对象进行锚布局
    button2.layoutData = layoutData2;

    Jan

    16

    HorizontalLayout 与 VerticalLayout :“水平”与“垂直”这两种自动布局对象是比较常用的。基本上大同小异,只是方向不同。Feathers 的容器组件如果带有 layout 属性,那么就支持使用这两种自动布局方式。

    1、两种对象都支持 horizontalAlign 与 verticalAlign 对齐方式,但被对齐对象的尺寸在方向上必须小于容器在同一个方向上的尺寸。比如 HorizontalLayout 对象如果想让这两个属性起作用,子对象的宽度必须小于设置了 layout 属性的容器对象的宽度。

    2、与对应的 HorizontalLayoutData、VerticalLayoutData 结合使用,可以支持百分比的方式布局子对象。如:

    var button1:Button = new Button();
    button1.label = "1";
    var button1LayoutData:HorizontalLayoutData = new HorizontalLayoutData();
    button1LayoutData.percentWidth = 25;//这个按钮水平方向占百分之25的宽度
    button1.layoutData = button1LayoutData;
    container.addChild(button1);

    var button2:Button = new Button();
    button2.label = "2";
    var button2LayoutData:HorizontalLayoutData = new HorizontalLayoutData();
    button2LayoutData.percentWidth = 75;//这个按钮水平方向占百分之75的宽度
    button2.layoutData = button2LayoutData;
    container.addChild(button2);

    还能方便的结合绝对尺寸与自动尺寸布局,如:

    var button1:Button = new Button();
    button1.label = "1";
    button1.width = 300;//绝对宽度300像素
    container.addChild(button1);

    var button2:Button = new Button();
    button2.label = "2";
    var button2LayoutData:HorizontalLayoutData = new HorizontalLayoutData();
    //虽然它写了100%,但它并不会与父容器的宽度相同,会先减去绝对尺寸对象(宽度300像素),剩下的才是它的
    button2LayoutData.percentWidth = 100;
    button2.layoutData = button2LayoutData;
    container.addChild(button2);

    HorizontalLayout 与 HorizontalLayoutData 对象结合自动布局时,也可以同时设置 percentHeight 的值,但子对象排序的方向是水平的(VerticalLayout 与 VerticalLayoutData 也一样支持 percentWidth 设置,但子对象排序是垂直方向的)。

    下面这样在同一个子对象上混合使用“绝对与相对”也可以

    var button1:Button = new Button();
    button1.label = "1";
    button1.width = 300;//宽度是300像素
    var button1LayoutData:HorizontalLayoutData = new HorizontalLayoutData();
    button1LayoutData.percentHeight = 100;//但高度是100%
    button1.layoutData = button1LayoutData;
    container.addChild(button1);

    var button2:Button = new Button();
    button2.label = "2";
    var button2LayoutData:HorizontalLayoutData = new HorizontalLayoutData();
    button2LayoutData.percentWidth = 100;//宽度占用了父容器减去300像素后剩余的全部宽度
    button2.layoutData = button2LayoutData;
    container.addChild(button2);

    通过 HorizontalLayoutData 构造函数可以快速的设置宽与高的相对百分比:

    new HorizontalLayoutData( 50100 )//width: 50%, height: 100%

    如果 HorizontalLayoutData 构造函数中传入 NaN 值表示在某个方向不设置百分比:

    button1.width = 300;
    button1.layoutData = new HorizontalLayoutData( NaN, 100 );

    但百分比的值总是优先使用的,如果既设置了对象的绝对尺寸,又同时通过 layoutData 属性设置了对象的百分比布局,那么起作用的是相对百分比布局,绝对尺寸设置将被忽略。

    3、默认情况下如果一个容器支持使用“虚拟化布局”(跟 Flex 列表项呈现器重用机制一样),那么 useVirtualLayout 默认为 true。一般来说很少被禁用。

    a、LayoutGroup 与 ScrollContainer 组件没有虚拟化布局的属性设置。

    b、默认情况下,启用虚拟化布局对象时的尺寸某一方向上宽度或高度相同,这有助于提高性能。

    c、设置 hasVariableItemDimensions  为 true 可以让每个项渲染器的尺寸不同,typicalItem 属性引用的对象被用于估算尺寸,但只有当数据真正被呈现的时候,才计算真实的尺寸用于精确的定位坐标。

    4、通过布局类能重新改变内置组件的布局,比如 List 和 GroupedList 默认都是垂直方面的,但也可以改成水平方向的。

    Jan

    16

    Feathers3 LayoutGroup 一些备注

    • 0 Comments
    • Flash Platform

    1、LayoutGroup 是一个轻量级的容器,无滚动条。默认通过手动方式绝对布置子对象的坐标,但也支持使用“自动布局对象”自动化布置子对象的坐标。

    通过 layout 属性可以与 HorizontalLayout 或 VerticalLayout 等自动化布局对象让子对象自动布局。

    2、LayoutGroup 不要子对象必须是 Feathers UI 的组件,可以是 Starling 显对象。

    3、LayoutGroup 默认情况下它的宽与高值是子对象的区域宽与高,但也可以手动修改宽与高。

    a、手动修改尺寸如果比子对象显示的区域还要小,子对象默认不会被“裁切”掉,但可以通过 clipContent 属性设为 true 进行裁切,但渲染性能会下降一些。

    b、clipContent 设为 true 之后 skipUnchangedFrames 属性依旧会起作用。

    4、LayoutGroup 最主要的皮肤相关的功能基本上就只有一个 backgroundSkin(背景皮肤)。

    比如一个 Starling 的 Image 对象,它会自动拉伸以匹配 LayoutGroup 宽与高。

    Jan

    16

    Callout 很类似 Alert 对象,也是通过调用一个静态的 show() 方法来显示的,参数基本类似,但有一个“目标源(origin)”参数用于定位 show() 显示的对象。

    TextCallout 扩展了 Callout  类,show() 的时候只渲染了一个文本对象。

    Jan

    16

    Button 的 Event.TRIGGERED 事件只有当 touch 开始与结束都在按钮上时才触发,如果在 touch 开始时,如鼠标或手指移到按钮的外面再释放(结束),那么是不会触发 Event.TRIGGERED 事件的;但如果 touch 开始后,鼠标或手指移到按钮外面,再移回到按钮上面,再结束,它还是会继续触发 Event.TRIGGERED 事件。

    ToggleButton 和 Button 大同小异。Event.CHANGE 事件可以侦听按钮的“开关”状态。Check 与 Radio 组件是 ToggleButton 子类,使用也类似。

    ButtonGroup 是一组水平或垂直布局的按钮组。dataProvider 会自动识别 ListCollection 对象中的字段。比如如下代码:

    group.dataProvider = new ListCollection(
    [
        { label: "One", triggered: oneButton_triggeredHandler },
        { label: "Two", triggered: twoButton_triggeredHandler },
        { label: "Three", triggered: threeButton_triggeredHandler },
    ]);

    ButtonGroup 对象会自动识别出 label 字段用于按钮的文本显示。其它类似:icon、isToggle、isSelected等这些字段都是可以用的(包括事件相关的字段比如 triggered、change 都可以用)。

    Jan

    16

    Feathers3 AutoComplete 一些备注

    • 0 Comments
    • Flash Platform

    AutoComplete 扩展了 TextInput 类,用于在输入时会弹出一个带有推荐选项的下拉列表。

    LocalAutoCompleteSource 默认会自动匹配包含输入的字符,既便输入的字符是属于单词的中间部份。如下代码中输入“ap”,除了匹配 Apple 外(这个 Apple 会自动被转换成小写的),还会匹配Grape。

    input.source = new LocalAutoCompleteSource( new ListCollection(new <String>
    [
        "Apple",
        "Banana",
        "Cherry",
        "Grape",
        "Lemon",
        "Orange",
        "Watermelon"
    ]));

    LocalAutoCompleteSource 还可以这样子自定义匹配方法:

    var source:LocalAutoCompleteSource = new LocalAutoCompleteSource();
    source.compareFunction = function( item:Object, textToMatch:String ):Boolean
    {
        return item.toString().toLowerCase().indexOf(textToMatch.toLowerCase()) == 0;
    };

    不过这个组件在移动开发时好像并没有多大用处……

    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 属性有半毛钱关系?我整个人都不好了。