About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • Jan

    26

    Feathers3 PageIndicator 一些备注

    • 0 Comments
    • Flash Platform

    PageIndicator 一般可滚动、却分页的组件一起使用,提供一系列的“符号(symbol)”,既在视觉上表示页面索引的位置,也可以直接用于点击导航页面。

    基本用法:

    var pages:PageIndicator = new PageIndicator();
    pages.pageCount = 5;
    this.addChild( pages );

    pageCount 表示页面数量,并且添加到显示列表后,如果没有进行任何设置,默认它的第一个符号是处于被选中状态。

    元素在进行排列的时候默认是水平布局的,也可以通过 direction 属性进行修改 Direction.HORIZONTAL 或 Direction.VERTICAL;还有其它一系列的布局相关的值可以提供简单的修改方式:

    pages.gap = 4;
    pages.paddingTop = 4;
    pages.paddingRight = 4;
    pages.paddingBottom = 4;
    pages.paddingLeft = 10;
    pages.horizontalAlign = HorizontalAlign.CENTER;
    pages.verticalAlign = VerticalAlign.MIDDLE;

    元素的普通状态与被选中的状态,分别可以使用 normalSymbolFactory 与 selectedSymbolFactory 样式属性进行设置,可以是任何 Starling 显示对象:

    pages.normalSymbolFactory = function():DisplayObject
    {
        return new Image( normalSymbolTexture );
    };

    pages.selectedSymbolFactory = function():DisplayObject
    {
        return new Image( selectedSymbolTexture );
    };

    当 PageIndicator 页面数量固定的情况下,被选择页面值更改时,这些元素对象是会被重复使用的(只是调整对象的位置,并不会从内存中销毁与重建)。

    Jan

    26

    Feathers3 NumericStepper 一些备注

    • 0 Comments
    • Flash Platform

    NumericStepper 组件通过加号或减号按钮修改数值,但如果 editing 被启用(比如在移动设备上 editing 是被禁用的)也可以通过文本框对象(text input)直接输入数值。

     基本用法样例代码:

    var stepper:NumericStepper = new NumericStepper();
    stepper.minimum = 0;
    stepper.maximum = 100;
    stepper.value = 50;
    this.addChild( stepper );

    最大值与最小值决定 NumericStepper 对鐌 的取值范围。但是请注意,此时没有设置 step 属性,点击加或减按钮并不会更改 NumericStepper 对象的值。所以同时需要设置一下 step 属性值:

    stepper.step = 1;

    还需要注意,如果 step 值被设为整数1,那么通过加减号按钮设置 NumericStepper 对象时 value 属性会变成整数。既似类似 value 值程序化的强制设为 4.5 ,当点击加号按钮时也会先被四舍五入到5,然再加 1,也就是变成 6;但如果将 step 的值设为浮点数,比如 0.1,那么 依旧还是会变成值 4.6。

    NumericStepper 组件的外面是由三部份组成的,分别是加、减号铵钮和一个文本对象(text input)。布局可以通过 buttonLayoutMode 属性值来调整;textInputGap 可以调整文本对象与按钮对象的间距;如果布局上两个按钮被放在文本框的同一侧,还可以通过 buttonGap 调整两个按钮之间的间距。

    Jan

    26

    Feathers3 DateTimeSpinner 一些备注

    • 0 Comments
    • Flash Platform

    DateTimeSpinner 是一组 SpinnerList 组成的组件,用来选择日期和时间。它支持多种编辑模式,允许用户只选择日期,只选择时间,或两者。

    var spinner:DateTimeSpinner = new DateTimeSpinner();
    spinner.editingMode = DateTimeMode.DATE;//设置显示日期、时间或同时显示
    spinner.minimum = new Date(197001);
    spinner.maximum = new Date(20501131);
    spinner.value = new Date(20151031);
    this.addChild( spinner );

    DateTimeSpinner 对象的 value 属性值代表当前选择的日期与时间值。minimum 与 maximum 属性值决定一个被选择日期与时间的范围(minimum 与 maximum 属性也可以省略设置,会自动选择一个合理的范围)。

    与其它大多数组件一样,设置皮肤外观两种方式,一种是通过主题文件(theme),另一种是没有主题文件(或不通过主题文件):

    通过主题文件设置样例代码: 

    getStyleProviderForClass( SpinnerList )
        .setFunctionForStyleName( DateTimeSpinner.DEFAULT_CHILD_STYLE_NAME_LIST, setDateTimeSpinnerListStyles );

    private function setDateTimeSpinnerListStyles( list:SpinnerList ):void
    {
        var skin:Image = new Image( texture );
        skin.scale9Grid = new Rectangle( 2316 );
        list.backgroundSkin = skin;
    }

    也可以在主题文件中自定义样式名称:

    spinner.customListStyleName = "custom-list";

    //通过 customListStyleName 样式属性名称设置
    getStyleProviderForClass( SpinnerList )
        .setFunctionForStyleName( "custom-list", setDateTimeSpinnerCustomListStyles );

    不通过主题文件设置皮肤外观,而是通过 listFactory 属性设置子组件的外观:

    spinner.listFactory = function():SpinnerList
    {
        var list:SpinnerList = new SpinnerList();

        //skin the lists here, if you're not using a theme
        var skin:Image = new Image( texture );
        skin.scale9Grid = new Rectangle( 2316 );
        list.backgroundSkin = skin;

        return list;
    }

    Jan

    25

    Feathers3 SpinnerList 一些备注

    • 0 Comments
    • Flash Platform

    SpinnerList 类是 List 类的子类,一个 SpinnerList 通常在用户进行滚动时会被设为无限循环,被选择项位于列表的中间,在视觉上用突出的颜色表示。

    SpinnerList 与常规的 List 类稍稍有些不同的地方,就是不能将 isSelectable 设为 false,否则就会抛出异常。因为 SpinnerList 使用的意图就是为了选择某一项。

    选择项在视觉上的高亮皮肤可以自定义,可以是任何 Starling 显示对象,如 starling.display.Image:

    list.selectionOverlaySkin = new Image( texture );

    皮肤是水平居中或垂直居中取决于滚动的方式。

    Jan

    25

    FlowLayout 用于显示从左向右的多行显示布局(如 List、LayoutGroup、ScrollContainer 等),支持水平或垂直分页,有许多简单的属性支持间距、对齐等设置。

    a、常用的简单属性如:padding、paddingTop、paddingRight、paddingBottom、paddingLeft、gap、horizontalGap、verticalGap、horizontalAlign、verticalAlign、 rowVerticalAlign 等等。

    b、支持虚拟化布局(关于虚拟化布局的备注资料参看《Feathers3 HorizontalLayout & VerticalLayout 一些备注》第3条)。

    WaterfallLayout 与上面的 FlowLayout 类似,但它是显示多个列的布局,每一项的宽度是相同的,高度可以不同。所有项会按顺序被添加到布局,但每一项可能会被添加到任何可用的一列中(布局标准为:在布局进行时被选择的列高度,再加上被添加项的高度产生的列高度尽可能的小)。

    a、常用的简单布局属性基本上与上面的 FlowLayout 类列举的类似。

    b、还可以通过 requestedColumnCount 属性指定请求布局的列数(容器的尺寸可能会比较小,请求的列数如果过多的话会无法按请求的列数布局,只会按最大可容纳的数量列数布局;但只要容器的尺寸足够大,就会按请求的列数进行布局)。如果容器没有手动指定容器的宽度,设置requestedColumnCount 属性值后,会按请求自动计算出容器的宽度。

    c、同样支持虚拟化布局。

    Jan

    25

    媒体播放器控件(Media player controls)用于控制媒体播放器,如播放、暂停、全屏、静音、播放头进度时间提示等等,在 Feathers 中的控件罗列:

    1、FullScreenToggleButton:用于控制切换视频播放器(VideoPlayer)全屏状态。

    2、MuteToggleButton:控制媒体播放器是否静音。

    3、PlayPauseToggleButton:控制播放与暂停。

    4、SeekSlider:控制播放头位置、进度提示。

    5、TimeLabel:显示当前时间、剩余时间或总时间。

    6、VolumeSlider:控制音量大小。

    Jan

    25

    Feathers3 VideoPlayer 一些备注

    • 0 Comments
    • Flash Platform

    VideoPlayer  通过 flash.net.NetStream 对象提供视频播放功能。视频文件可以是一个  URL 地址来源,并作为 Starling 纹理显示。媒体播放器控件(Media player controls)可以作为视觉元素 / 控件添加到 VideoPlayer 对象中,比如播放、暂停、当前的时间进度等元素。VideoPlayer 类是 LayoutGroup 类的子类,所以子元素可以通过布局对象进行布局。

    最基本的流程:

    var player:VideoPlayer = new VideoPlayer();
    player.setSize( 320300 );//设置尺寸
    this.addChild( player );//添加到显示列表
    player.videoSource = http://example.com/video.m4v;

    视频中的每一帧画面会成为 Starling 中的纹理对象,所以我们使用 ImageLoader 对象来显示纹理:

    //添加一个 ImageLoader 对象作为 VideoPlayer 的子对象用于显示视频纹理
    var loader:ImageLoader = new ImageLoader();
    player.addChild( loader );

    此时还没有设置 ImageLoader 的 source 属性。在 GPU 上需要一些时间初始化视频纹理用于 Starling 的渲染,一旦可以将纹理传递给 ImageLoader,VideoPlayer 对象就会调度 Event.READY 事件(在 Event.READY 事件派发之前,VideoPlayer 对象的 texture 属性值是 null)。

    function videoPlayer_readyHandler( event:Event ):void
    {
        loader.source = player.texture;//视频纹理可以通过 texture 属性访问
    }
    player.addEventListener( Event.READY, videoPlayer_readyHandler );

    同时还需要侦听 Event.CLEAR 事件,当视频纹理被销毁时将会派发此事件:

    function videoPlayer_clearHandler( event:Event ):void
    {
        loader.source = null;
    }
    player.addEventListener( Event.CLEAR, videoPlayer_clearHandler );

    添加一些视觉元件控件可以用于控制视频的播放:

    var controls:LayoutGroup = new LayoutGroup();
    controls.styleNameList.add( LayoutGroup.ALTERNATE_STYLE_NAME_TOOLBAR );//作为一个 toolbar 添加
    player.addChild(controls);

    var button:PlayPauseToggleButton = new PlayPauseToggleButton();
    controls.addChild( button );

    var slider:SeekSlider = new SeekSlider();
    controls.addChild( slider );

    这两个控件都是 Feathers 提供的内置的“媒体播放器控件”,不需要为它们编写任何业务逻辑代码就能控制视频的播放。

    视频加载的几种方式:

    a、如上面的网络 URL 地址:

    player.videoSource = http://example.com/video.mp4;

    b、本地文件地址(本质上它还是一个 URL 地址):

    var videoFile:File = File.applicationDirectory.resolvePath("video.mp4");
    player.videoSource = videoFile.url;//这里一定要记得使用 url 属性,如使用 nativePath 不会起作用的

    c、从流媒体服务器加载,类似商业的 Adobe Media Server 或开源的 Red5 Media Server ,通过 netConnectionFactory 属性连接服务器,然后在 videoSource 属性设置视频流的名称:

    player.netConnectionFactory = function():NetConnection
    {
        var nc:NetConnection = new NetConnection();
        nc.connect("rtmp://localhost/vod");
        return nc;
    };
    player.videoSource = "mp4:streams/myvideo";

    如果是同一个服务器上不同的视频流,只需要更改 videoSource 属性的视频流的名称就可以。

    Jan

    25

    Feathers3 SoundPlayer 一些备注

    • 0 Comments
    • Flash Platform

    SoundPlayer 支持 URL 加载或从一个 Sound 对象加载,媒体播放器控件(Media player controls)可以作为视觉元素 / 控件添加到 SoundPlayer 对象中,比如播放、暂停、当前的时间进度等元素。SoundPlayer 类是 LayoutGroup 类的子类,所以子元素可以通过布局对象进行布局。

    最基本用法的样例代码:

    var player:SoundPlayer = new SoundPlayer();
    this.addChild( player );//如果不想添加视觉元件,也可以不添加到显示列表
    player.soundSource = http://example.com/sound.mp3;

    比如,添加一些视觉元素控件可以用于控制音频的播放:

    var button:PlayPauseToggleButton = new PlayPauseToggleButton();//添加一个暂停按钮
    player.addChild( button );

    var slider:SeekSlider = new SeekSlider();//添加一个播放头控制控件
    player.addChild( slider );

    这两个控件都是 Feathers 提供的内置的“媒体播放器控件”,不需要为它们编写任何业务逻辑代码就能控制音频的播放。

    如上样例,SoundPlayer 类结合了媒体播放器控件后,无论是播放音频还是控制音频都变的十分方便。

    Jan

    22

    自定义项渲染器(custom item renderers)一般是通过扩展现成的 Feathers LayoutGroup 子类实现的,或者自行实现对应的接口(实际上就是创建自定义的 Feathers 组件并实现指定的接口类型)。

    扩展现成的 LayoutGroup 子类一般是指扩展以下三个类:

    LayoutGroupListItemRenderer 作为 List 的项渲染器
    LayoutGroupGroupedListItemRenderer 作为 GroupedList 的项渲染器
    LayoutGroupGroupedListHeaderOrFooterRenderer 为作 GroupedList 的 header 或 footer 项渲染器

    扩展这些子类创建自定义的渲染器好处就是已经实现了必要接口所需要的业务逻辑并进行了优化,一些基础功能和常用的方法都被提供了(比如data、index、owner 属性等)。坏处就是它有可能会稍稍的降低一些性能(个人觉的可以忽略不计)。

    实现对应的接口一般指扩展 FeathersControl 这个抽象的基类,并实现 IListItemRenderer、IGroupedListItemRenderer、IGroupedListHeaderOrFooterItemRenderer 这三个接口(因为一般都是通过扩展 LayoutGroup 子类可以方便的实现自定义项渲染器,所以实现接口不是我要备注的资料,以下就省略了)。

    一般流程如下(如果熟悉 Flex 的话估计也会很熟悉):

    1、CustomItemRendererClass 类扩展某个 LayoutGroupXXXXXXRenderer 类,然后通过 itemRendererFactory 或 itemRendererFactory 来赋值提供给列表使用。

    通过列表类组件的 itemRendererFactory 属性可以设置 List 的对象的自定义的项渲染器,如:

    list.itemRendererType = CustomItemRendererClass;

    也可以通过列表类组件的 itemRendererFactory 属性设置,如:

    list.itemRendererFactory = function():IListItemRenderer
    {
        var renderer:CustomItemRendererClass = new CustomItemRendererClass();
        return renderer;
    };

    2、编写 CustomItemRendererClass 类的具体业务逻辑代码,如在生命周期的资料中备注的,推荐覆盖 initialize() 方法,添加子对象、侦听器(这些侦听器一般是不打算移除的,直到渲染器被 disposed() 方法调用销毁)、使用布局类对象进行布局等初始化相关的代码,而不是放在构造函数中。

    也有一些例外,比如将一些事件侦听器添加在 FeathersEventType.RENDERER_ADD 的侦听器中,一般很少用这种(可能偶尔会在大数据并结构虚拟化布局时可能会用到),最终确保在 FeathersEventType.RENDERER_REMOVE 的侦听器中移除对应的事件侦听器。

    3、解析 data 对象,简单的覆盖 commitData() 方法(比如项渲染器中有一个 Label 组件):

    override protected function commitData():void
    {
        if(this._data)
        {
            this._label.text = this._data.label;
        }
        else
        {
            this._label.text = null;//不要忘了设为 null 避免运行时产生错误
        }
    }

    4、如果要添加其它属性,就使用 setter 方法,最后需要用 invalidate() 方法失之失效再重新验证(其它的样式布局相关的操作都如同在 LayoutGroup 中一样):

    protected var _padding:Number = 0;

    public function get padding():Number
    {
        return this._padding;
    }

    public function set padding(value:Number):void
    {
        if(this._padding == value)
        {
            return;
        }
        this._padding = value;
        this.invalidate(INVALIDATION_FLAG_LAYOUT);
    }

    5、覆盖 preLayout() 方法,用于更新子对象的布局属性(发生在项渲染器的 layout 代码运行之前,还可以覆盖 postLayout() 方法,它发生在项渲染器的 layout 代码运行之后,一般不会用到它)。

    一份简单而完整的自定义项渲染器代码样例:

    ……

    在 “Feathers Cookbook” 还有许多现成的关于自定义项渲染器的片段代码样例:

    a、自定义项渲染器添加背景皮肤

    b、处理触摸状态

    c、通过点击或触屏选择一个自定义项渲器

    d、当一个自定义项渲染器被触碰时防止列表滚动

    e、派发一个“开关”事件

    f、派发一个长按事件

    More...

    Jan

    22

    Feathers3 “组件生命周期(Feathers Component Lifecycle)”经历以下几个过程:

    1、实例化(Instantiation)

    通过关键字 new 生成对象,此时组件还没有被添加到显示列表上,可以任意修改属性,此时组件不会进行任何渲染,直到它被添加到显示列表中才会对显示相关的属性作出反应。有一个宗旨就是尽量减少在构造函数中初始化相关的代码量(除非是没有被添加到显示列表前,就需要确定的初始化相关的代码才 需要在构造函数中完成),初始化相关的代码尽量放在下面介绍的 initialize() 方法中。

    2、初始化(Initialization)

    组件被添加到显示列表后,initialize() 方法被自动调用,这个方法只会在组件第一次被添加到显示列表时被调用(只会被调用一次,如果将它从显示列表移除,再重新添加也兴地再次运行),开发者可以覆盖这个方法进行子对象相关的布局,其它初始化相关的代码也要尽量放在这个方法体内,尽量减少构造函数中初始化相关的代码。这个方法体内的所有代码执行结束后,会派发一个 FeathersEventType.INITIALIZE 事件,表示初始化方法 initialize() 执行结束了。

    如果一个组件在被添加到显示列表前调用了 validate() 方法,那么 initialize() 方法会被立即执行(请注意:FeathersEventType.INITIALIZE 与 FeathersEventType.CREATION_COMPLETE 事件也会被派发;后续的操作再将这个组件添加到显示列表时就不会再执行 initialize() 方法,也不会再派发这些事件了)。

    3、应用主题样式(Apply theme styles)

    一般来说,使用 Feathers 进行开发的时候,都会有一个主题文件(theme,也不排除一些开发者会直接在业务逻辑相关的类中直接进行皮肤样式的设置而不使用主题文件,但这是不推荐的),在 FeathersEventType.INITIALIZE 事件派发后,会立即应用主题文件的样式属性设置到组件上(如果没有主题文件, 此过程就被跳过了)。

    4、验证(Validation)

    组件进入第一次验证阶段,此时组件的所有属性就好像都已失效(关于失效,查看下面的 Invalidation 过程介绍),会进行一次完成的属性处理。当第一次验证结束后,会派发一个 FeathersEventType.CREATION_COMPLETE 事件(也就是在第一次 draw() 方法后会派发这个事件)。

    当进行验证操作的时候,组件会调用 draw() 方法,任何组件已更改的属性会在 draw() 方法中进行处理。如果对组件没有进行手动坐标、尺寸设置,组件需要根据预置配置相关的数据,自动计算用于布局的尺寸(包括最小值),用于预置自动计算相关的值机会被传递给 saveMeasurements() 方法,计算出最终布局尺寸。组件根据需要调整子对象的坐标与尺寸等。

    a、请注意:这里的 draw() 并不是真正的渲染对象,而只是表示对绘制时的数据处理,决定需要重绘的属性,真正的绘制过程是下面的 render() 方法对应的渲染过程。

    b、在创建自定义组件的时候,draw() 方法既简单,又有用,通过它就能完成验证步骤。

    c、在 draw() 方法中,调用 isInvalid() 方法可以判断某个属性是否失效的,是否需要重绘的(如果调用 isInvalid() 方法时没有传入失效类型参数,那么任意的一个失效标志(flags)都会返回 true)。

    d、如果没有手动设置组件的宽与高,在验证步骤中,saveMeasurements() 方法就会被调用,根据子组件、皮肤、样式布局等设置,来自动计算组件的尺寸。

    e、isQuickHitAreaEnabled 属性它有点类似于传统显示对象中的 mouseChildren 属性,它可以大大提高点击碰撞测试的性能(touch hit tests),如果子组件不需要碰撞检测,可以用它来优化性能。它会将碰撞检测简化为对一个 actualWidth 与 actualHeight 的矩形(自动计算出来的)碰撞检测。

    f、Feathers 组件 width 与 height 属性的设置与读取取决于多个因素,这两个值在通过 setter 方法设置时内部对应的是私有的 _explicitWidth 与 _explicitHeight 属性值,当手动设置的时候,就会更改 _explicitWidth 与 _explicitHeight 属性,再通过 getters 方法返回的也就是对应的 _explicitWidth 与 _explicitHeight 属性值;只读属性 explicitWidth 与 explicitHeight 也会暴露“ _explicit”私有值,explicitWidth 与 explicitHeight 两个值也是用于布局的值。如果没有手动设置 width 与 height 属性,那么就会被自动计算出来,最终结果会被传递给 saveMeasurements() 方法。

    5、渲染(Render)

    Feathers 显示相关的组件都是 Starling 显示对象,所以它有一个 render() 方法,Starling 会在每一帧调用这个方法(Feathers 组件通常不会覆盖 Starling 的 render() 方法),在组件 render()方法被调用前,总是会执行验证步骤。

    6、失效 (Invalidation)

    接下来,当组件的属性出现变化时,组件需要将对应属性失效的类型参数(一个或多个)传递给 invalidate() 方法,通常它在一个 setter 方法体内,失效的类型参数可以是代表尺寸、布局、选择状态的等等。每个组件可能会有一些自己独特的失效类型参数,但一些常用的失效类型参数已经作为常量被定义在 FeathersControl 这个基类上了。失效类型参数如何使用没有任何强制规则,可以随意调用 invalidate() 方法不传入任何参数。

    在组件“失效”后,组件就会进入等待“验证”的步骤(此时也可以手动强制执行 validate() 方法进入验证步骤,比如想立即得到组件的宽与高值,这些值是在验证步骤中计算的) ,在到达渲染步骤前,属性可能再次发生改变或其它属性也可能发生改变。当组件进入渲染步骤的时候,会确保所有属性更改已提交(committed)到渲染的需求。

    失效→验证→渲染,这个循环的过程会一直进行,直到组件从显示列表被移除,它才会停止;如果再次被添加到显示列表,这个过程就会又继续。

    7、移除 (Removal)

    组件从显示列表被移除后,就不会再自动进入验证步骤,所有属性的更改会被保存,但不会再被提交(committed)到渲染的需求里。除非它再次被添加到显示列表,才会重新开始进入验证步骤。如果组件不在显示列表上(不在舞台上),也想让组件也进入“验证”步骤,需要手动调用组件的 validate() 方法。

    8、销毁(Disposal)

    与 Starling 显示对象一样,Feathers 的组件也有 dispose() 方法,用来移除事件侦听器、纹理、子对象等。一个组件被销毁后自然就不能再进行验证了。被调用 dispose() 方法不应该是被添加在显示列表上的对象(需要先将它从显示列表移除),否则就可能产生运行时异常或失去所有响应。

    9、垃圾回收(Garbage Collection)

    当组件的所有引用被去除的时候,它就适合被垃圾回收器回收了(垃圾回收器的回收工作是不可控制的)。