英文原文: Flex 4 Gumbo DOM Tree API - Functional and Design Specification
翻译的原创链接: http://www.smithfox.com/?e=36 转载请注明, 文中如果有什么错误的地方或是讲的不清楚的地方,欢迎大家留言.
这是一篇难得的Flex功能和架构技术SPEC, 耐心看完绝对有收获.
为了振作你看这个文章的兴趣, 假设你应聘Flex工作被问到了下面的几个问题:
1. Flex中owner和parent有什么区别?
2. addChild和addElement两套函数有什么不同,(不是指怎么使用不同, 而是指框架内部的设计有什么不同)?
3. <s:Rect>是GraphicElement吗, 他们为什么可以放在<s:Group>内?
4. SkinnableComponent, SkinnableContainer, Group, DataGroup以及SkinnableDataContainer有什么区别?
5. 最关键的是: 你知道smithfox吗?(哈哈)
目的
在Flex 4中有许多DOM(Document Object Model)树。他们到底是怎么组织和呈现的?
定义
图形元素(graphic element) - 就象是矩形, 路径, 或是图片. 这些元素不是DisplayObject的子类; 但是它们还是需要一个DisplayObject来渲染到屏幕. (smithfox注: "多个图形元素可以只用一个DisplayObject来渲染")
视觉元素(visual element) - (英文有时简称为 - "element"). 可以是一个halo组件, 或是一个gumbo组件, 或是一个图形元素. 视觉元素实现了接口 IVisualElement.
数据项 (英文有时简称为 - "item") - 本质上Flex中的任何事物都可以被看着数据项. 通常是指非可视化项,比如 String, Number, XMLNode, 等等. 一个视觉元素也能作为数据项 -- 这要看他是怎么被看待的.
组件树 - 组件树表现了MXML文档结构. 举个简单例子, 一个 Panel 包含了一个 Label. 这个例子中, Panel 和 Label 都在组件树中, 但是 Panel的皮肤却不是.
布局树 - 布局树呈现了运行时的布局. 在这个树中, 父亲负责呈现和布局对象, 孩子则是被布局的视觉元素. 举个简单例子, 一个 Panel 包含了一个 Label. 这个例子中, Panel 和 Label 都在布局树中, 同样Panel的皮肤和皮肤中的contentGroup也是.
显示树 - Flash 底层 DisplayObject 树.
本文中的全部图的图例如下:
背景:
当你用MXML创建应用程序时, 幕后发生了许多的事情,会将MXML转换成Flash显示对象. 后台有三个主要因素: 皮肤,项渲染和显示对象sharing. 前两个对开发人员是非常重要的概念; 最后一个只需要框架开发人员关注, 但仍然比较重要.
皮肤:
当你初始化一个 Button, 其实创建了不止一个对象. 例如:
<s:Button />
在布局树中的结果是:
(注: TextBox 已经更名为 Label)
一个皮肤文件被实例化了,并且加入到Button的显示列表中.Button的皮肤文件如下:
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" minWidth="23" minHeight="23"> <fx:Metadata> [HostComponent("mx.components.Button")] </fx:Metadata> <s:states> <s:State name="up" /> <s:State name="over" /> <s:State name="down" /> <s:State name="disabled" /> </s:states> <!-- background --> <s:Rect left="0" right="0" top="0" bottom="0" width="70" height="23" radiusX="2" radiusY="2"> <s:stroke> <s:SolidColorStroke color="0x5380D0" color.disabled="0xA9C0E8" /> </s:stroke> <s:fill> <s:SolidColor color="0xFFFFFF" color.over="0xEBF4FF" color.down="0xDEEBFF" /> </s:fill> </s:Rect> <!-- label --> <s:Label id="labelDisplay" /> </s:Skin>尽管Button看上去是一个叶子结点, 但因为皮肤的存在, 实际上他包含了孩子. 为访问这些元素,所有SkinnableComponent对象都定义了skin属性. 这样就可以通过Button.Skin实例来访问Rectangle 和Label. 如要访问Label, 你可以写成:myButton.skin.getElementAt(2)或是 myButton.skin.labelDisplay.由于labelDisplay是 Button 的 skin part, 所以你可可以直接写成 myButton.labelDisplay.
同样的原则也一样适用在SkinnableContainer. SkinnableContainer是容器所以天然就有孩子, 但同时他们也是SkinnableComponent,所以也有一个皮肤以及来自皮肤的孩子.
(smithfox注: SkinnableContainer的确是继承自SkinableComponent, 见图)
还是以Panel为例:
<s:Panel> <s:Button /> <s:Label /> <s:CheckBox /> </s:Panel>panel有三个孩子:一个button,一个label,和一个checkbox.用定义在SkinnableContainer上的content APIs可以访问他们. 这些content APIs很像flash DisplayObjectContainer 的 APIs, 包括addElement(), addElementAt(), getElementAt(), getElementIndex(), 等等.... 所有方法的完整列表在稍后文档中列出.
因为 panel有3个孩子, 它的组件树象这样:
(注: TextBox 已经更名为 Label)
但是, 这只是组件树. 因为皮肤的原因, Panel真正布局树是这样的:
(注: TextBox 已经更名为 Label)
在上面这张图上有许多箭头. 需要注意的有:
- Panel的组件孩子有: button, label, 和checkbox.
- button, label, 和checkbox的组件父亲(owner 属性) 是 Panel.
- button, label, and checkbox的布局父亲 (parent 属性) 是 Panel皮肤的contentGroup.
这意味着即使看上去Panel的孩子应该是一个button, 一个label, 和一个checkbox; 但实际上真正的孩子是一个panel皮肤实例. button, label, 和 checkbox 向下变成了皮肤中contentGroup的孩子. 有几种方法可以访问panel中的Button: myPanel.getElementAt(0) or myPanel.contentGroup.getElementAt(0) or myPanel.skin.contentGroup.getElementAt(0).
所有 SkinnableComponent 都有 skin 属性. 在 SkinnableContainer中组件的孩子实际上下推成为skin的 contentGroup的孩子. 组件树 指向编译自MXML的语义树.Panel 例子中, 只包括Panel 和他的孩子: 一个 button, 一个 label, 和一个checkbox. 由于皮肤, 布局树 是布局系统所实际看到的树.Panel 例子中,包括 这个panel, panel的皮肤, 以及这个皮肤的所有孩子(皮肤中的contentGroup的孩子).
布局树无需和所见的Flash显示列表有什么相关性. 这是因为 GraphicElement 不是天然的显示对象. 因为考虑效率的原因, 他们最小化了显示对象数目(smithfox注: 多个GraphicElement可以在一个DisplayObject上渲染, 这样DisplayObject的总数就可以大大减少).
(smithfox注: GraphicElement是spark的类, 确实是少有继承层次非常少的对象, 如图:)
IVisualElementContainer 定义了content APIs. 在Spark中, Skin, Group, 和 SkinnableContainer 实现了这个接口,持有着可视化元素. 为保持一致性, MX的 Container 也实现了这个接口, 不过只是对addChild(), numChildren, 等函数的封装....
package mx.core { public interface IVisualElementContainer { //---------------------------------- // Visual Element iteration //---------------------------------- /** * The number of elements in this group. * * @return The number of visual elements in this group */ public function get numElements():int; /** * Returns the visual element that exists at the specified index. * * @param index The index of the element to retrieve. * * @return The element at the specified index. * * @throws RangeError If the index position does not exist in the child list. */ public function getElementAt(index:int):IVisualElement //---------------------------------- // Visual Element addition //---------------------------------- /** * Adds a visual element to this visual container. The element is * added after all other elements and on top of all other elements. * (To add a visual element to a specific index position, use * the <code>addElementAt()</code> method.) * * <p>If you add a visual element object that already has a different * container as a parent, the element is removed from the child * list of the other container.</p> * * @param element The element to add as a child of this visual container. * * @return The element that was added to the visual container. * * @event elementAdded ElementExistenceChangedEvent Dispatched when * the element is added to the child list. * * @throws ArgumentError If the element is the same as the visual container. */ public function addElement(element:IVisualElement):IVisualElement; /** * Adds a visual element to this visual container. The element is * added at the index position specified. An index of 0 represents * the first element and the back (bottom) of the display list, unless * <code>layer</code> is specified. * * <p>If you add a visual element object that already has a different * container as a parent, the element is removed from the child * list of the other container.</p> * * @param element The element to add as a child of this visual container. * * @param index The index position to which the element is added. If * you specify a currently occupied index position, the child object * that exists at that position and all higher positions are moved * up one position in the child list. * * @return The element that was added to the visual container. * * @event elementAdded ElementExistenceChangedEvent Dispatched when * the element is added to the child list. * * @throws ArgumentError If the element is the same as the visual container. * * @throws RangeError If the index position does not exist in the child list. */ public function addElementAt(element:IVisualElement, index:int):IVisualElement; //---------------------------------- // Visual Element removal //---------------------------------- /** * Removes the specified visual element from the child list of * this visual container. The index positions of any elements * above the element in this visual container are decreased by 1. * * @param element The element to be removed from the visual container. * * @return The element removed from the visual container. * * @throws ArgumentError If the element parameter is not a child of * this visual container. */ public function removeElement(element:IVisualElement):IVisualElement; /** * Removes a visual element from the specified index position * in the visual container. * * @param index The index of the element to remove. * * @return The element removed from the visual container. * * @throws RangeError If the index does not exist in the child list. */ public function removeElementAt(index:int):IVisualElement; //---------------------------------- // Visual Element index //---------------------------------- /** * Returns the index position of a visual element. * * @param element The element to identify. * * @return The index position of the element to identify. * * @throws ArgumentError If the element is not a child of this visual container. */ public function getElementIndex(element:IVisualElement):int; /** * Changes the position of an existing visual element in the visual container. * * <p>When you call the <code>setElementIndex()</code> method and specify an * index position that is already occupied, the only positions * that change are those in between the elements's former and new position. * All others will stay the same.</p> * * <p>If a visual element is moved to an index * lower than its current index, the index of all elements in between increases * by 1. If an element is moved to an index * higher than its current index, the index of all elements in between * decreases by 1.</p> * * @param element The element for which you want to change the index number. * * @param index The resulting index number for the element. * * @throws RangeError - If the index does not exist in the child list. * * @throws ArgumentError - If the element parameter is not a child * of this visual container. */ public function setElementIndex(element:IVisualElement, index:int):void; //---------------------------------- // Visual Element swapping //---------------------------------- /** * Swaps the index of the two specified visual elements. All other elements * remain in the same index position. * * @param element1 The first visual element. * @param element2 The second visual element. */ public function swapElements(element1 :IVisualElement, element2 :IVisualElement):void; /** * Swaps the visual elements at the two specified index * positions in the visual container. All other visual * elements remain in the same index position. * * @param index1 The index of the first element. * * @param index2 The index of the second element. * * @throws RangeError If either index does not exist in * the visual container. */ public function swapElementAt(index1:int, index2:int):void; } }
这个接口使访问树变得容易了. 本质上, 这个接口为容器对外暴露有它哪些孩子提供了方法. 例如, FocusManager就是这样. 该接口使得 focus manager不依赖于Group 或是其它 Spark代码(除了这个接口), MX也不必增加太多代码. 我们讨论过要不要增加这些变异的(mutation) APIs,要不要MX也实现这些接口, 但我们认为这将有助有开发人员(框架开发人员) 实现所有容器(MX和Spark). 当我们看 DataGroup and SkinnableDataContainer 代码时, 你会发现他们并没有实现IVisualElementContainer接口, 尽管DataGroup有几个相似的 "只读的" 方法, 比如 numElements 和 getElementAt().
(smithfox注: 从Spark最终SDK中的代码可以验证, 如图)
IVisualElementContainer 持有 IVisualElements. IVisualElement 是可视化元素的一个新接口. 它包含了一些必要的属性和方法以使容器可以增加element. 他继承自 ILayoutElement 并增加了一些其它属性.
//////////////////////////////////////////////////////////////////////////////// // // ADOBE SYSTEMS INCORPORATED // Copyright 2003-2008 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file // in accordance with the terms of the license agreement accompanying it. // //////////////////////////////////////////////////////////////////////////////// package mx.core { /** * The IVisualElement interface defines the minimum properties and methods * required for a visual element to be laid out and displayed in a Spark container. */ public interface IVisualElement extends ILayoutElement { /** * The owner of this IVisualElement object. * By default, it is the parent of this IVisualElement object. * However, if this IVisualElement object is a child component that is * popped up by its parent, such as the drop-down list of a ComboBox control, * the owner is the component that popped up this IVisualElement object. * * <p>This property is not managed by Flex, but by each component. * Therefore, if you use the <code>PopUpManger.createPopUp()</code> or * <code>PopUpManger.addPopUp()</code> method to pop up a child component, * you should set the <code>owner</code> property of the child component * to the component that popped it up.</p> * * <p>The default value is the value of the <code>parent</code> property.</p> */ function get owner():DisplayObjectContainer; function set owner(value:DisplayObjectContainer):void; /** * The parent container or component for this component. * Only visual elements should have a <code>parent</code> property. * Non-visual items should use another property to reference * the object to which they belong. * By convention, non-visual objects use an <code>owner</code> * property to reference the object to which they belong. */ function get parent():DisplayObjectContainer; ...OTHER STUFF NOT DISCUSSED HERE... } }
(smithfox注: IVisualElement接口为什么是放在mx.core包内,确实有点怪, 但这是事实, 如图)
视觉元素的parent, 也就是容器, 直接负责布局. 视觉元素的owner是视觉元素的逻辑持有组件. 如果一个 Button在一个SkinnableContainer里, 它的parent是contentGroup而它的owner 是这个 SkinnableContainer.
请注意 parent 和 owner 属性类型是 DisplayObjectContainer 而不是 IVisualElementContainer. 这是因为在MX内, 这些属性就是
DisplayObjectContainer. 此外, 因为 parent 属性是继承自 Flash的 DisplayObject, 我们无法改变他. 我们曾讨论过为这个属性起个新名字, 但最后我们认为这样不值得.
(smithfox注: DisplayObjectContainer是flash.display.Sprite的父类)
相关推荐
Flex4中文API文档详细记录了AS3的各种类库、方法、属性和事件,帮助开发者理解和利用这些功能。 1. **Flex Framework**:Flex框架包括一系列组件、服务和工具,用于构建用户界面。它提供了MXML,一种声明式语言,让...
总的来说,Flex 4.0中文API文档是开发者学习Flex 4.0框架的关键资源,它详细解释了如何使用Flex组件、事件、服务以及如何利用Spark组件模型来创建高度定制化的用户界面。通过查阅这个CHM文档,开发者可以快速掌握...
在本压缩包中,重点是Flex的中文API和开发指南,这对于初学者和有经验的开发者来说都是宝贵的资源。 首先,让我们来了解一下Flex API。API,全称Application Programming Interface,是一系列预先定义的函数,允许...
这个"flex 中文API"是针对初学者的中文版文档,旨在帮助开发者快速理解并掌握Flex编程的核心概念和API用法。 1. **Flex SDK与Flex Builder** Flex SDK是一个开源工具集,包含了编译Flex应用所需的编译器、库和...
在本文中,我们将深入探讨Flex API的核心概念、主要特点以及如何使用它来开发动态、互动的Web应用。 1. **Flex SDK与Flex API** Flex SDK(Software Development Kit)是一套免费的开发工具,包含编译Flex应用程序...
总的来说,Flex4中文API帮助文档是Flex开发者不可或缺的工具,它覆盖了Flex4的所有核心功能,包括组件、MXML、ActionScript、布局、动画、服务集成等多个方面,对于学习和掌握Flex4开发技术至关重要。无论你是初学者...
在军标箭头库的实现中,开发者可能利用了ArcGIS Flex API的图形对象和符号系统来绘制各种军标箭头,这些箭头可以表示战术动作、方向或兵力部署等。 另一方面,SuperMap Flex API则是SuperMap公司为Flex开发者提供的...
总的来说,Flex 4.0 API中文手册是开发者深入学习Flex开发不可或缺的资源,它详尽地涵盖了从基础概念到高级特性的各个方面,帮助开发者熟练掌握Flex 4.0框架,创造出功能丰富、交互性强的RIA应用。
我见到过的最好用的flex4 chm api,非常完整,超级帮 最新Flex4.6中文API,离线帮助文档,无js错误
这个版本的Flex引入了全新的设计和编程模型,极大地增强了开发者创建复杂、动态且具有高度交互性的Web应用的能力。Flex 4.0中文API文档是为中文开发者提供的官方参考手册,帮助他们理解和运用Flex 4.0的各类功能和...
Flex中文API文档是学习和使用Flex的关键资源,它详尽地解释了每个类、方法、属性和事件,对于初学者和经验丰富的开发者来说都是不可或缺的工具。通过深入研究这个文档,开发者可以熟练掌握Flex的各个方面,构建出...
在Flex 4.5.1版本中,引入了一系列改进和新特性,为开发者提供了更强大的功能和更好的用户体验设计。这个"flex4.5.1.chm"文件是一个完整的Flex 4 API文档,它是开发人员的重要参考资料,包含了大量的类库、函数、...
Flex 4 中文API 绝对的好东西 不是损坏的
总的来说,Adobe Flex 3 API为开发者提供了一个全面的框架,帮助他们构建功能强大、视觉吸引人的RIA。通过学习和掌握这个API,开发者可以创建出高度交互、响应迅速的Web应用程序,同时利用Adobe的技术栈实现广泛的...
1. **Flex API**:Flex API是Flex框架的核心组成部分,提供了大量的类库和接口,用于创建和管理组件、处理事件、进行数据绑定、网络通信等。例如,`mx.controls`包下的Button、Label、TextInput等控件,以及`mx....
综上所述,“Flex中文API”是一份宝贵的资源,对于想要理解和掌握Flex框架的开发者来说,无论英语水平如何,都能从中受益。通过深入学习这些文档,开发者将能够熟练地运用Flex构建高效、美观的RIA。
中文版的Flex API 文档对于中国开发者来说是一份非常有价值的参考资料,它可以帮助开发者更方便地理解和使用Flex框架。 Flex是Adobe公司开发的一个开源框架,基于ActionScript编程语言,用于构建跨平台的、基于...
在“flex3-cn-api..zip_flex_flex 3 api_flex3 api_flex3 a_flex3 api”这个压缩包中,包含了Flex 3 API的中文文档,这对于Flex开发者来说是一个非常宝贵的资源。文档名为“Flex3拞暥API..chm”,其中的“拞暥”可能...
Flex 4.5 API 是Adobe Flex框架的一个重要版本,它为开发者提供了丰富的工具和技术来创建交互式的、基于Web的应用程序。这个API集成了ActionScript 3.0,使得开发人员可以利用面向对象的编程能力来构建高效且动态的...