About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • Jan

    26

    文本渲染器(也有人称“文本呈现器”,text renderers)在 Feathers 的帮助页面上列在了“核心内容”部份,这个核心的意思大概是指文本渲染器涉及到多个组件的组成部份。在 GPU 上显示文本有多种方式,但每一种方式都有优点与缺点,并没有任何一种最好的方式,所以凡是涉及到文本的组件,都给开发者提供了对应的 API 允许开发者自己选择不同的文本渲染器。

    在选择不同的文本渲染器时应考虑以下几个因素:

    1、文本的长度
    2、多更新一次文本(文本更新的频率)
    3、文本所显示的语言

     这些因素可能会影响性能与内存的使用量,具体取决于选择的文本渲染器。在单个场景中不同组件可以混合使用不同的文本渲染器,以达到最佳效果。

    Feathers 提供了 3 种不同的文本渲染器

    1、BitmapFontTextRenderer:使用位图字体(bitmap fonts)作为文本渲染器的内容。它的好处是同一张纹理图可以用于多个文本渲染器实例,多个实例同时使用时可以大大减少绘制命令的调用(Starling 对相同纹理的渲染有优化);运行时的动态生成的渐变、滤镜效果等是很占性能的、且需要更多系统资源的,所以可以对位图字体先预处理效果,将渐变、滤镜等特效变成位图字体的一部份,这样就能大大提高性能、并节省系统资源。缺点是它一般不推荐用在需要大量的字符的情况下,比如汉字……或者需在大量不同字体字号的的情况下。

    2、TextBlockTextRenderer:先使用 Flash 内置的文本 Engine(Flash Text Engine)软渲染,然后将结果 draw 下来变成位图数据对象(BitmapData),再转换成 Starling 需要的纹理格式提交到 GPU 使用,它提供的版式功能是最丰富的,包括像亚洲字体从左向右的版式都可以有,但每个实例需要一份单独的纹理对象,因此,如果场景中有多个对象使用了这种文本渲染器,它不仅会增加原生 API 的 draw 次数,也同样会增加 Starling 的 draw 次数(当然文本生成的位图面积越大,性能与内存开销越大)。

    3、TextFieldTextRenderer:先使用的是 flash.text.TextField 软渲染,然后将结果 draw 下来变成位图数据对象(BitmapData),再转换成 Starling 需要的纹理格式提交到 GPU 使用,TextField 可以支持一个 HTML 标签的子集,但它的版式功能很有限。每个实例需要一份单独的纹理对象,因此,如果场景中有多个对象使用了这种文本渲染器,它不仅会增加原生 API 的 draw 次数,也同样会增加 Starling 的 draw 次数(同样 TextBlockTextRenderer 一样,文本生成的位图面积越大,性能与内存开销越大)。

    每一种文本渲染器的功能并不相同,所以一定要仔细区分,选择一个最佳的文本渲染器应用到开发中。

    默认的文本渲染引擎:

    通常情况下,应用程序中的大多数组件将使用相同类型的文本渲染器。为避免重复的在每个组件中单独设置文本渲染器,可以先设置一个全局的文本渲染器告诉所有组件默认情况下使用某种文本渲染器。只有当遇到某个组件不需要默认的文本渲染器时,才给它传递入特殊的文本渲染器,覆盖默认的类型。

    推荐使用 BitmapFontTextRenderer,Starling 与 Feathers 的使用目的主要目标之一就是开发游戏,字符串比较短(相当于 draw 的面积比较小),并且需要经常性的更新。

    当使用主题文件时(theme),应该检查默认的文本渲染器。主题文件中通常会嵌入一种自定义字体,通用于组件的文本渲染,保持风格一体化。

    当一个组件没有单独设置文本渲染器的时候,它会调用 FeathersControl.defaultTextRendererFactory() 方法。FeathersControl.defaultTextRendererFactory 是一个静态变量,可以根据需要任意的更改为不同的函数,默认它就是这样子:

    function():ITextRenderer
    {
        return new BitmapFontTextRenderer();
    }

     根据需要,也可以更改为 TextBlockTextRenderer 作为默认的文本渲染器:

    FeathersControl.defaultTextRendererFactory = function():ITextRenderer
    {
        return new TextBlockTextRenderer();
    };

    在单个组件上使用不同的文本渲染器:

    可以给特定的组件指定特殊的文本渲染器,不使用(覆盖)默认的文本渲染器,比如一个按钮:

    button.labelFactory = function():ITextRenderer
    {
        return new TextFieldTextRenderer();
    }

    甚至可以在返回文本渲染器之前,对文本渲染器设置字体相关的高级选项:

    button.labelFactory = function():ITextRenderer
    {
        var textRenderer:TextFieldTextRenderer = new TextFieldTextRenderer();
        textRenderer.antiAliasType = AntiAliasType.NORMAL;
        textRenderer.gridFitType = GridFitType.SUBPIXEL;
        return textRenderer;
    }

    如果正在使用主题文件进行开发,需要小心:当对单个组件设置 labelFactory 属性时,可能被主题文件中的样式覆盖,因为主题文件中样式的使用是在单个组件设置 labelFactory 之后

    不同的组件在指定文本渲染器时可能会有不同的属性名称,比如一个 Header 对象,它不叫 labelFactory,而是叫 titleFactory。任何组件的文本渲染器样式工厂属性名称可以通过查询 API 手册

    Label 组件

    Label 组件是一个具体的组件,它可以非常方便和简单的显示文本,但它本身不是文本渲染器,但它包含了文本渲染器实例。

    通常,我们不会去直接使用一个 BitmapFontTextRenderer 对象,Label 组件可以很好的抽象出具体使用功能但分离文本渲染器,文本渲染器应该脱离实际的应用开发,这样可以快速的切换不同的主题文件、应用不同的样式等操作。Label 组件有一个 fontStyles 样式属性,它可以接受一个 starling.text.TextFormat 对象,不同的对象可以接受不同的格式化相关的类,如 flash.text.engine.ElementFormat 或 feathers.text.BitmapFontTextFormat 类。特别是当大批的文本对象使用的时候,如果后期要更改与前期选择的文本渲染器不同的,那么可能要在很多不同的类文件中一个一个的去修改……

    自定义文本渲染器

    自定义文本渲染器的时候,需要实现 ITextRenderer 接口类,它有一些预置的方法,比如将字符串赋值给文本渲染器,文字的测量。一个自定义的文本渲染器可能是基于 Text Layout Framework (TLF) 的,它提供了更高级的功能。除非自定义的文本渲染器是能够直接渲染到 GPU 的,否则就需要一个“快照”,类似前面的 TextFieldTextRenderer 或 TextBlockTextRenderer ,先 draw 到一个位图数据,再转换成 Starling 需要的纹理格式提交到 GPU 使用(Feathers 是开源的,可以参考它内置的文本渲染器源码)。

    其它的备用方案

    在显示文本方面,还有其它一些备用方案,但它们和前面提供的几个文本渲染器一样,都有它们各自的优点与缺点。

    Feathers 的 ScrollText 组件:因为纹理图有尺寸限制,有时候我们的文本对象可能太宽或太高超出了限制,或者整体尺寸过大,没有足够的 GPU 显存可能存储纹理;极少数的时候,我们可能可以用 BitmapFontTextRenderer 对象来解决这种问题,但它并不适合矢量对象。此时,我们应该考虑一下使用 ScrollText 组件,它的文本渲染引擎是一个原生舞台上的 flash.text.TextField 对象,原生舞台始终在 Stage3D 层上面(CPU 软渲染的)。它会被自动计算匹配到 Starling 对象的坐标系统中。

    a、ScrollText 最大的缺点就是它在移动设备上渲染大量文本时可能会跟不上性能,比如滚动时可能会无法“平滑”,出现跳帧。

    b、ScrollText 另外的缺点就是原生舞台层始终在 Stage3D 层上面,所以无法在 ScrollText 组件上添加其它 Starling 对象。

    c、另外一些潜在的问题,如在安卓设备上,原生层与Stage3D 层帧频设置对半分,以及 Starling 的 skipUnchangedFrames 属性很可能会被禁用等。

    关于 skipUnchangedFrames 属性被禁用的资料请参看《skipUnchangedFrames 属性局限性》。

    Jan

    26

    Feathers3 ToggleSwitch 一些备注

    • 0 Comments
    • Flash Platform

    ToggleSwitch 在视觉上就是一个开关按钮,控制 on 和 off 的状态。可以当成是 Check 另一种风格的组件,滑块可以用手指滑动或点击切换状态。

    ToggleSwitch组件由on 和 off 文本、滑块、以及一个或两个轨道组成。

    1、on 和 off 文本:

    toggle.onLabelFontStyles = new TextFormat( "Helvetica"20, 0xcc0000 );
    toggle.offLabelFontStyles = new TextFormat( "Helvetica"20, 0x000000 );
    //如果禁用时的文本字体样式与普通常不一样,同样可以设置
    toggle.onLabelDisabledFontStyles = new TextFormat( "Helvetica"20, 0x9a9a9a );
    toggle.offLabelDisabledFontStyles = new TextFormat( "Helvetica"20, 0x9a9a9a );

    2、轨道与布局:轨道一般是一个或两个按钮组成的,trackLayoutMode 属性决定轨道由几个按钮组成(默认值是 TrackLayoutMode.SINGLE,单个轨道),如果想在按钮的两侧分别有两个不同的轨道按钮,可以将值设为 TrackLayoutMode.SPLIT。当值为 TrackLayoutMode.SINGLE 时,只有一个 on 状态的轨道会一直填充整个组件的区域,不会有 off 状态的轨道出现。

    3、滑块:它其实也是一个按钮……

    轨道与滑块都是按钮组件,所以普通的按钮组件常用的功能与外观设置的方法一般都适用于它们。

    Jan

    26

    Feathers3 PickerList 一些备注

    • 0 Comments
    • Flash Platform

    PickerList  组件显示一个按钮,在点击按钮后会弹出一个选择列表(pop-up List),通过修改 pop-up 的弹出内容,可以为不同的平台定制不同的弹出列表对象;弹出的列表对象可以通过 popUpContentManager 属性设置,用不同的方式显示,类似下拉的菜单、 Callout、或者是一个叠加的模态化窗口(列表与舞台宽度相同)等。

    基本使用流程, new 一个对象并添加到显示列表:

    var list:PickerList = new PickerList();
    this.addChild( list );

    然后通过 ListCollection 对象赋值给 dataProvider 属性,就可以通过弹出的 List 对象获取选择数据:

    var groceryList:ListCollection = new ListCollection(
    [
        { text: "Milk" },
        { text: "Eggs" },
        { text: "Bread" },
        { text: "Chicken" },
    ]);
    list.dataProvider = groceryList;

    设置弹出的 List 对象(创建项渲染器,并指定项渲染器的 labelField 属性需要使用的对应字段):

    function createItemRenderer():IListItemRenderer
    {
        var itemRenderer:DefaultListItemRenderer = new DefaultListItemRenderer();
        itemRenderer.labelField = "text";
        return itemRenderer;
    }
    function createPopUpList():List
    {
        var list:List = new List();
        list.itemRendererFactory = createItemRenderer;
        return list;
    }
    list.listFactory = createPopUpList;

    被选择对象的标签(label)也需要显示在按钮上,因为我们还需要将值传到 PickerList  对象的 labelField 属性上:

    list.labelField = "text";

    请注意上面的两次设置的 labelField ,前一次是在弹出的 List 组件对象上,后一次是在 PickerList  组件对象上(自定义项渲染器并不强制要 labelField 属性,所以 PickerList 对象并不能从弹出的 List 对象自动检测这个属性,所以需要手动分别指定两次)。

    默认情况下会选中第一项数据,PickerList  按钮上显示的是第一项数目,但也可以手动设置不选择任何项,只给出一些文字提示(prompt 属性),如:

    list.prompt = "Select an Item";
    //如果要使用 prompt 属性起作用,必须把 selectedIndex 设为 -1,表示不选择任何项
    list.selectedIndex = -1;

    通过 popUpContentManager 属性可以自定义弹出列表的行为,常用的三种对象:

    1、VerticalCenteredPopUpContentManager 类似一个安卓系统上的居中显示的选择 UI 界面。

    2、CalloutPopUpContentManager 类似一个 Callout 组件,并有一个箭头指向点击的按钮目标源。

    3、DropDownPopUpContentManager 类似一个下拉菜单。

    创建自定义的弹出列表的行为控件相关的类,需要实现 IPopUpContentManager 接口类。

    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 属性的视频流的名称就可以。