深入浅出Flex4 移动应用组件的生命周期.doc_第1页
深入浅出Flex4 移动应用组件的生命周期.doc_第2页
深入浅出Flex4 移动应用组件的生命周期.doc_第3页
深入浅出Flex4 移动应用组件的生命周期.doc_第4页
深入浅出Flex4 移动应用组件的生命周期.doc_第5页
已阅读5页,还剩31页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1 深入浅出 Flex4 Mobile 组件的生命周期 前言 Flex 开发移动应用时 出于性能考虑 需要使用 AS3 编写组件 Skin 而不是使用 MXML 实际上 通过使用 AS3 编写组件皮肤 开发者可以更 深入的了解 Flex 的组件生命周期 无论是对于移动应用开发还是传统的桌面或者 Web 应用开发 都大有裨益 本文通过一个实例 来展示如何使用 AS3 开发一个 Spark 组件和对应的移动组件 Skin 更重要的是解释与之相关的 Spark 组件生命周期知识 关于本系列文章 Spark 架构的目的就是分离组件行为和可视化 在 Spark 框架中 组件的数据和逻辑行为由组件类负责 而可视化剥离到 Skin 中 组件和其 Skin 间维护一个所谓的 契约 本文不具体解释 Spark 架构的基本概念 如果您不了解 Spark 的基础知识 可以参考 Deepa 姐姐的文章 Spark 架构和组件集的简要概述 本文将为你揭示 Spark 架构背后的秘密 本文介绍的内容和例子是基于 Flex4 5 的移动架构上 但是其中关于 Spark 架构的介绍 99 通用于非 移动框架的 Spark 组件 为了更好的理解本文 建议您下载 Flex4 5 SDK 源码 我们的终极目标 Flex 移动应用中 最频繁使用的组件之一可能就是 ponents LabelItemRenderer 和 ponents IconItemRenderer 了 IconItemRenderer 继承自 LabelItemRenderer 而 LabelItemRenderer 扩展了 UIComponent 这里有一点问题 如果参看 Adobe 官方文档 Using Adobe Flex4 5 在 Create advanced Spark visual components in ActionScript 一章有如下描述 Create a skinnable component by creating a subclass of the SkinnableComponent class A skinnable component uses two files one for the component definition and one for the skin definition Create a Spark skinnable component as a subclass of the SkinnableComponent class Spark 体系的 Skinnable 组件应该是继承自 SkinnableComponent 每一个组件包含两个文件 一个是组件类 继承自 SkinnableComponent 一个是皮肤类 很显然 IconItemRenderer 和 LabelItemRenderer 都不属于 SkinnableComponent 其弊端在于 每次如果你需要深度定制 ItemRenderer 都不得不扩展这两个类 覆盖其中相关方法 Part1 的目标是使用 ActionScript 创建一个真正 Skinnable 的 ItemRenderer 为了简单起见 我们以 LabelItermRenderer 为例 2 一 开发 Spark 组件和 mobile 应用适用的 Skin 类的步骤 B 车追上 A 车 需要一个步骤 电 A 车 而创建 Spark 架构下 Skinnable 的组件需要两个主要步骤 创建负责数据和非可视化逻辑的组件类 该类将继承 SkinnableComponent 本 例中需要额外两个接口 mx core IDataRenderer 和 ponents IItemRenderer 以便最终用于 List 的 ItemRenderer 创建负责 可视化的 Skin 类 由于我们的目标是为移动应用创建组件 Skin 因此该类继承 spark skins mobile supportClasses MobileSkin 最复杂 的是把大象关进冰箱 具体方法超出本文讨论范畴 二 创建 Flex 手机项目 启动 FlashBuilder4 5 点击 文件 新建 创建 Flex 手机项目 如下图 跟随向导选择手机操作系统和应用模板 本例中选择的模板是 基于视图的应用程序 FlashBuilder 将为我们创建空的手机应用项目 在本例 中 我们最终所创建项目的项目结构如下 3 三 创建 Component 类 1 创建继承SKINNABLECOMPONENT 实现 IDATARENDERER 和 IITEMRENDERER 的 AS3 类 MOBILEITEMRENDERER AS 在 src 目录下 创建路径为 ponents 的 package 在该 package 下 通过菜单 新建 ActionScript Skinnable 组件 创建 Skinnable 组件类 在创建向导中 如下图 指定该类名为 MobileItemRenderer 可以看到该类的超类默认设置为 ponents supportClasses SkinnableComponent SkinnableComponent 是所有符合 Spark 架构的 Skinnable 组件类的基类 其父类是 UIComponent 我们在 Part3 中会深入讨论这个类 4 同时 由于我们要创建可以被 List 使用的 itemRenderer 因此需要实现 IDataRenderer 和 IItermRenderer 两个接口 把两个接口添加 到接口列表中 点击 完成 后 我们就得到了 FlashBuilder 自动创建的 半成品 在 MobileItemRenderer 的半成品中 FlashBuilder 已经创建了实现 接口所需要的 Set 和 Get 空方法 2 完成需要的IDATARENDERER 和 IITEMRENDERER 接口方法 出于简化目的 本例中并不完成所有的接口方法 我们主要实现 data itemIndex 和 selected 的 set 和 get 方法 实现 IDataRenderer 接口的 data 的 set 和 get 方法之目的在于使我们自定义的 MobileIterRenderer 能够从 List 中获取到数据 实现 IItemRenderer 接口的 itemIndex 和 selected 的 set 和 get 方法的目的是 能够从 List 获取到条目的用户选择状态和 index 关于两个接口的具体说明请参见 AS3 参 考中的 IItemRenderer 和 IDataRenderer 说明 首先创建三个变量 private var itemIndex int private var data Object private var selected Boolean false 接下来 分别完成 data 的 set 和 get 方法 以及 itemIndex 的 get 方法 itemIndex 的 set 方法比较复杂 本例暂不实现 如果你希望进 一步了解 可以参考 ponents LabelItemRenderer 类源码中的 itemIndex set 方法 Bindable dataChange public function get data Object 5 return data private public function set data value Object void data value if hasEventListener FlexEvent DATA CHANGE dispatchEvent new FlexEvent FlexEvent DATA CHANGE public function get itemIndex int return itemIndex public function set itemIndex value int void 此方法本例中暂不实现 public function get selected Boolean return selected public function set selected value Boolean void if selected value selected value 6 我们之后还会修改 selected 的 set 方法 因为该属性的变化会触发我们自定义的 component 类 MobileItemRenderer 的状态变化 3 声明 SKINPART SkinPart 实际上最终就是 Skin 类的一个子组件 由 Skin 类将其加入到显示列表 或者从其中删除 而 component 类则声明本 component 需要哪些 SkinPart 对应的 Skin 类要严格照办 我们的 MobileItemRenderer 类极其简陋 只需要一个用来展示 label 信息的 SkinPart 因此 我们声明 StyleableTextField 类型的 SkinPart 如下 其名称为 labelDisplay 设置 required true 要求 MobileItemRenderer 的配套 Skin 类必须提供名为 labelDisplay 的 部件 即变量 该变量必须为 StyleableTextField 或者其子类类型 Part3 问题一 为嘛 Skin 一定要提供与 SkinPart 指定名称一致的部 件变量 为嘛类型必须一致 public class MobileItemRenderer extends SkinnableComponent implements IDataRenderer IItemRenderer SkinPart required true public var labelDisplay StyleableTextField 4 覆盖 PARTADDED 和 PARTREMOVED 方法 当 Skin 类将对应的 SkinPart 加入到显示列表中时 通过 addChild component 类会调用 partAdded 方法 当移除时 会调用 partRemoved 方法 partAdded 和 partRemoved 使我们可以在 SkinPart 加入显示列表或者从显示列表中移除时获得通知 并在 component 类中做相应的操作 比如 我们可以覆盖这两个方法为 SkinPart 添加或删除事件侦听器等 Part3 问题二 component 类如何知道 skin 类添加了 SkinPart 继而 来调用 partAdded 呢 本例中 我们覆盖这两个方法来加入 double click 的事件侦听器 当用户双击 component 类的 labelDisplay 时 修改显示文本 如下 override protected function partAdded partName String instance Object void super partAdded partName instance if partName labelDisplay labelDisplay addEventListener MouseEvent DOUBLE CLICK changeLabel 7 override protected function partRemoved partName String instance Object void super partRemoved partName instance if instance labelDisplay labelDisplay removeEventListener MouseEvent DOUBLE CLICK changeLabel private function changeLabel event MouseEvent void var obj StyleableTextField event target as StyleableTextField obj text 小心雷电 partAdded 方法的参数 partName 说明了加入到显示列表中的部件名称 该名称对应之前 SkinPart 声明的变量名 如果有多个 SkinPart 则应对应其中某个 instance 为加入到显示列表中的 SkinPart 对象 在本例中即为 Skin 类通过 addChild 加入进来的 StyleableTextField 类型的 labelDisplay 对象 我们可以如 partAdded 方法中一样通过 partName 来判断 也可以如 partRemoved 方法中使用 instance 来判断加入的对象是哪个 SkinPart 在这个例子中我们使用 partAdded 和 partRemoved 修改了 label 的显示 实际上 同样的工作也可以放在 Skin 中进行 从技术上讲 并没 有一个严格的界限说明类似的操作必须在 component 类中执行或者必须在对应的 Skin 类中执行 这个界限是模糊的 Part3 问题三 为什么我们通过这两种方式都可以判断加入的对象是哪个 SkinPart 为什么我们可以使用 component 类的 labelDisplay 来注册侦听器 我们并没有实例化该 labelDisplay 因此上述代码应该抛出 null 异常吗 难道我们不 是应该使用传递进来的 instance 来注册事件侦听器吗 5 声明 SKINSTATE 接下来 为我们的组件声明状态 MobielItemRenderer 只有两个状态 normal 和 selected 状态声明要在类外 SkinState normal SkinState selected public class MobileItemRenderer extends SkinnableComponent implements IDataRenderer IitemRenderer 8 默认情况下 组件的状态为 normal 当 List 通知 item 被选中后 通过 selected 的 set 方法设置 selected 为 true 时 则组件状态变 为 selected 当 selected 变为 false 时 则状态切换回 normal 在 Flex 应用中 组件数据模型的变化会引发组件状态的变化 而状态的变化 则会触发可视界面的变化 因此 component 类本身并不负责处理状态 component 类仅仅声明了 Skin 类的状态 并根据数据模型的变化来反馈当 前状态 而 Skin 类要负责针对不同状态实现可视化效果 由此可见 我们需要修改 selected 的 set 方法 通知 Skin 类 状态发生了变化 我们通过调用 invalidateSkinState 方法 来通知对应 的 Skin 类状态发生了变化 而 Skin 类会在下一帧时来渲染新状态下的界面 Skin 类是通过 Component 类的 getCurrentSkinState 方法获取新状态的 part3 问题四 invalidateSkinState 是如何通知 Skin 类的呢 6 覆盖 GETCURRENTSKINSTATE 方法 component 类通过 getCurrentSkinState 方法来通知 Skin 类当前状态 在该方法中 我们通过 component 类的数据模型来判断当前处于 哪种状态 override protected function getCurrentSkinState String var returnState String normal1 if selected returnState selected return returnState part3 问题五 Skin 类是如何调用 getCurrentSkinState 的呢 目前为止 我们已经创建了一个非常基本的 component 类 实际上我们没有为该类实现一点点关于可视化的部分 这写任务都将由 Skin 类来完 成 而 Spark 组件生命周期中最神秘也最有趣的地方就是 component 类是如何同与其对应的 skin 类相互配合互动的 在本系列的 Part2 我们将为 MobileItemRenderer 创建 Skin 类 并提出更多问题 四 创建 CSS 我们首先创建将要在 Skin 类中使用的 CSS 样式文件为 Style css 建在 src 的 styles 目录下 代码如下 9 CSS file namespace s library namespace components ponents components MobileItemRenderer fontSize 20 color FF0000 font family sans min height 50 padding left 10 为了应用样式 在主应用文件 本例为 SparkItemRendererDemo mxml 中加入样式声明 五 AS3 创建 Skin 类 MobileItemSkin as 下面 我们的重头戏开始了 使用 AS3 为之前的 component 类 MobileItemRenderer 创建配套的 Skin 类 1 创建 MobileItemSkin as 在 com mark demos skins 包下创建 ActionScript 类 MobileItemSkin as 该类继承 spark skins mobile supportClasses MobileSkin 10 使用 Flex 开发移动应用项目时 Flex4 5 提供了一套专为移动设备优化了的类库和组件 这些类和组件为移动设备的优化包括性能和 DPI 自适 应等等 其中 MobileSkin 发挥了非常重要的作用 这个类是所有适配移动应用的 ActionScript Skin 类的基类 我们在 Part4 会解释如何使用 AS3 开发适配 Web 或桌面的 Spark 组件的 Skin 类 这时我们会继承 spark skins SparkSkin 值得注意的 是 MobileSkin 的父类是 UIComponent 在 Part3 我们会深入讨论 MobileSkin 和 SparkSkin 现在 让我们跳出代码 重新考虑 Spark 的 Skinnable 组件这件事情 现在我们已经知道 要创建两个类 一个 component 类 一个 skin 类 而两个类都是继承于 UIComponent 从这 一点上来说两个类没什么本质上的区别 只不过通过 Flex 框架代码 来让一个类管理数据和逻辑 一个类管理样式和外观 下面我们来逐步完成 Skin 类 MobileItemSkin as 在这个过程中 您不碍多想一想这个类是如何和 component 类协同的呢 2 hostComponent 11 每个 Skin 类都要声明它的宿主 hostComponent Skin 类的存在目的就是为 Component 类服务的 失去了 Component Skin 类就失去了 意义 一列失去灵魂的列车奔驰得再快 也没有任何价值 Using Flex 4 5 中说明 a skin class will define a hostComponent property so that is can get a reference to the component that uses it This is not required by the skinning contract but is recommended Skin classes can also share data with their host component by using data binding hostComponent 帮助 Skin 从 Component 中 拉 数据 通过这种方式获取开发者设定在 component 类上的属性以及相关变化 下面代码为我们的 MobileItemSkin 类 设定了 hostComponent 需要注意的是 hostComponent 的类型 MobileItemRenderer 如我们之前 说到的 Skin 类为 Component 类提供的服务是 专项 服务 因此 这里 hostComponent 类型必须与本 Skin 类的服务目标 component 类类型一 致 private var hostComponent MobileItemRenderer public function get hostComponent MobileItemRenderer return hostComponent public function set hostComponent value MobileItemRenderer void hostComponent value 3 createChildren 接下来 我们要为 component 类来 组装 Skin 在本例中 就像 MobileItemRenderer 中通过 SkinPart 元数据标签已经说明的 我们要为 其装配一个 StyleableTextField 或其子类类型的文本 我们并不是一步到位的为 Skin 生成该对象 并安装到位 还记得吗 Flex 架构非常重要 的工作就是 延迟计算 因此 首先 我们要做的只是 创建子对象 createChildren 我们通过覆盖 createChildren 方法来完成这项任务 很多时候 编写自定义组件感觉就像完成一道填空题 尤其对那些刚刚掌握创建自定义 组件的开发者来说 我们尽量在 Part3 来为您指明这些 填空 题的出题者的思路和想法 我们来完成第一项填空题 覆盖 createChildren 方法 在此之前 你需要声明一个 StyleableTextField 类型的变量 labelDisplay 这 帮助你完成了 Component 和 Skin 类之间的一项 契约 public class MobileItemSkin extends MobileSkin public var labelDisplay StyleableTextField 下面是 createChildren 方法真正完成创建 labelDisplay 的方法 在该方法中使用 addChild 把 labelDisplay 添加在显示列表中 12 override protected function createChildren void addLabel private function addLabel void labelDisplay new StyleableTextField addChild labelDisplay 4 commitProperties 如果你了解 UIComponent 的生命周期 你应该知道在 UIComponent 的生命周期中 Flex 会依序调用 createChildren commitProperties measure layoutChrom 和 updateDisplayList 方法 这些方法依次完成了各自专有的任务 其中 方法 commitProperties measure 和 updateDisplayList 会在 UIComponet 创建后 调用 invalidateProperties invalidateSize 和 invalidateDisplayList 方法后 在下一帧时再次被调用 鉴于 MobileSkin 父类依然是 UIComponent 因此这些基本原理依然适用 Part3 问题 如果你是一个究甚解的开发者 你会注意到在 Skinnable Spark Component 这个体系里存在着 Component 类和 Skin 类两个 UIComponent 子类 也就意味着 在 Skinnable Component 的生命周期中 存在着之前我们说到的两套 UIComponent 生命周期 在深入理解 Spark Component 生命周期的过程中 这个事实经常会混淆开发者 在本例中 我们使用 Skin 类的 commitProperties 来为 labelDispaly 定义外观属性 代码如下 override protected function commitProperties void mitProperties styleLabel private function styleLabel void if labelDisplay 13 if currentState normal labelDisplay text hostComponent data label labelDisplay defaultTextFormat new TextFormat getStyle fontFamily getStyle fontSize getStyle color labelDmitStyles 5 measure 我们已经设定了 labelDisplay 的外观 接下来 我们需要告知 Flex 本组件的默认最小尺寸和默认尺寸 覆盖 measure 方法 override protected function measure void super measure var h Number 0 var w Number 0 if labelDisplay w labelDisplay textWidth getStyle paddingLeft h labelDisplay textHeight measuredMinHeight getStyle minHeight measuredHeight Math max h measuredMinHeight measuredWidth w measuredMinWidth Math max unscaledWidth w 在上述代码中 我们通过 getStyle 获取 CSS 样式单中指定的 minHeight 来确定最小值 如果你深入阅读 LabelItemRenderer as 和 IconRenderer as 源码 你会发现 measure 方法要考虑的问题很多 本例中做了简化 14 6 layoutContents 方法 按照 UIComponet 的 填空题 应试法则 下面我们应该完成的是 UpdateDisplayList 方法 来实现最终的布局 但是 MobileSkin 覆盖了 UIComponent 类的 UpdateDisplayList 方法 新的 UpdateDisplayList 方法摘录于下 override protected function updateDisplayList unscaledWidth Number unscaledHeight Number void graphics clear super updateDisplayList unscaledWidth unscaledHeight layoutContents unscaledWidth unscaledHeight if useSymbolColor applySymbolColor drawBackground unscaledWidth unscaledHeight 可以看到 updateDisplayList 的主要工作被分为 layoutContents 和 drawBackground 两个方法 因此 对于创建移动应用组件皮肤 我 们很少会直接覆盖 updateDisplayList 方法 而是覆盖 layoutContents 和 drawBackground 方法 本例中 我们覆盖 layoutContents 方法来布置我们的部件 labelDisplay override protected function layoutContents unscaledWidth Number unscaledHeight Number void var labelWidth Number 0 var labelHeight Number 0 if labelDisplay labelDisplay width unscaledWidth labelDisplay x getStyle paddingLeft labelDisplay y unscaledHeight labelDisplay textHeight 2 we draw a separator line between each item var lineY int unscaledHeight 1 graphics clear 15 graphics lineStyle 1 graphics moveTo 0 lineY graphics lineTo unscaledWidth lineY 我们设置了 labelDisplay 的坐标 并且在其下边缘绘制了一条 1 像素的横线 7 更新状态 实际上 现在你就可以使用 MobileItemRenderer 了 但是如果你把他作为 itemRenderer 赋给 List 后 运行后 你会发现 MobileItemRenderer 并没有及时的响应用户操作 更新状态 我们还需要覆盖神秘的 commitCurrentState 方法 来为 Skin 类更新状态 override protected function commitCurrentState void mitCurrentState styleLabel 如果你看过 Part1 你会记得 我们已经为 Component 类 MobileItemRenderer as 声明了 SkinState normal 和 selected 在用户选 中本 item 后 List 会调用 selected 的 set 方法 然后该方法又会调用 invalidateItemState 来通知 Flex 更新状态 我们也按照要求 让 Component 类 MobileItemRenderer 乖乖的提供了方法 getCurrentSkinState 来通知某人我目前的状态 而在我们的 Skin 类中 很明显 某个神秘先生又通过 currentState 变量告知了当前状态 而前提是 我们要乖乖的实现 commitCurrentState 方法 各位看管 明白了吗 Flex 在布一个很大的局 有一双 手 在操控着 不明真相的群众 群众们只要按要求做好填空题 自然有全国最牛拜的机构 相关机构 帮你把文章写完 然而 作为一个有智商的现代码农 我们要求信息透明 因此 不才在 Part3 中将为你解释这个神秘的相关机构 我们的 commitCurrentState 方法如下 override protected function commitCurrentState void mitCurrentState styleLabel 16 六 调用 MobileItemRenderer 完成 View 目前 我们已经完成了 Component 类和 Skin 类 比较简陋 但是在 Part3 您会看到他的价值 完成示例项目中的 SparkItemRendererDemoView mxml 测试这个 MobileItemRenderer 17 运行后 您会得到如下结果 七 未完待续 上帝花七天创造了世界 问题是 他是怎么做的呢 如果你依照步骤看完了 Part1 和 Part2 那么 这也许是最 疑惑重重 的教程之一 我们为您演示了如何创建一个 Spark 架构下 Skinnable 组件类 但是 又带了了如此多的问题 为什么 Skin 一定要提供与 Component 类中 SkinPart 指定名称一致的部件变量 Component 类中的 SkinPart 和 Skin 类中的对象有何关系 component 类如何知道 skin 类添加了 SkinPart 继而来调用 partAdded 呢 partAdded 中 我们直接使用了 labelDisplay 来添加侦听器 可 labelDispaly 从何而来 与 instance 是和关系 invalidateSkinState 是如何通知 Skin 类的呢 Skin 类是如何调用 getCurrentSkinState 的呢 component 类和 skin 类之间的 契约 源于何处 18 Skin 类和 Component 类如何协同 两套 UIComponent 生命周期又如何交错在一起 currentState 从何而来 component 类的 commitProperties 方法和 Skin 类的 commitProperties 方法 八 前言 本文的讨论基于 Flex4 5 源码 并不是出自 Adobe 官方资料 讨论的内容和准确度处于本人理解和网络公开资料 欢迎各位发表意见 本文将以适配于移动应用的 Skinnable Spark 组件为例 讨论 Spark 组件的生命周期管理 其中大部分内容应该适用于桌面和 Web 的 Spark 组件生命周期 但对于传统的 Halo 组件生命周期会有不同 但殊途同归 本文会引述 Part1 和 Part2 中的示例来做讨论 如果你没有阅读过 Part1 和 Part2 建议提前阅读 九 生命周期的背后之手 了解 Flex 的组件生命周期 先要消除 恐惧感 确实不像想象的那么深奥 说穿了 就是要理解写这个架构的工程师们到底怎么想的 怎么设 计的 而最佳途径就是看源码 生命周期管理中 有几个类是核心所在 也就是我所说的 生命周期的背后之手 组件其实就像木偶 这些 手 来 操控指挥 木偶 的提线 Flash 提供了广阔的舞台 这些手包括 ponents supportClasses SkinnableComponent mx core UIComponent ponents supportClasses SkinnableComponent spark skins mobile supportClasses MobileSkin spark skins SparkSkin mx managers LayoutManager 十 Spark 组件的生命周期 关于 组件生命周期 的官方描述 可以参见 About creating advanced MX components 本节小人打算依据 Part1 和 Part2 示例 和您一起实地考察一番 1 Component 类 MobileItemRenderer 构造之前 List 之 addChild 19 对于一个组件来说 比如 MobileItemRenderer 生命起于其 AS 类的构造器 然而从应用角度看 MobileItemRenderer 被构建是由于其容 器要把他添加到显示列表中 以 MobileItemRenderer 为例 MobileItemRenderer 实例化是由于 List 的 DataGroup 部件要把他作为 ItemRenderer 的实例添加进来 我们简要的看一下来龙去脉 TIPS 在了解组件生命周期时 设置断点 并观察调用堆栈 可以帮助我们更加容易和清晰的了解 Flex 框架背后的调用过程 我们在 MobileItemRenderer 类的构造器中设置端点 如下图 设置断点 运行应用 在调用堆栈中可以看到如下结果 上述堆栈很清晰的显示了 Flex 是如何开始构造 MobileItemRenderer 的 我们从 Datagroup 开始 DataGroup 是 List 组件的 SkinPart 在 ListSkin as 中 createChildren 方法中加入了该部件 override protected function createChildren void if dataGroup Create data group layout var layout VerticalLayout new VerticalLayout layout requestedMinRowCount 5 layout horizontalAlign HorizontalAlign JUSTIFY layout gap 0 20 Create data group dataGroup new DataGroup Group itemRenderer new ClassFactory ponents LabelItemRenderer 如调用堆栈所示 DataGroup 的 measure 方法最终通过 ClassFactory 的 newInstance 调用了 MobileItemRenderer 类的构造器 在 DataGroup as 的 measure 方法中 调用了 ensureTypicalLayoutElement override protected function measure void if layout super measure DataGroup as 的 ensureTypicalLayoutElement 方法又调用 initializeTypicalItem 方法 private function initializeTypicalItem void if typicalItem null setTypicalLayoutElement null return var renderer IVisualElement createRendererForItem typicalItem false var obj DisplayObject DisplayObject renderer if obj setTypicalLayoutElement null return 21 super addChild obj setUpItemRenderer renderer 0 typicalItem if obj is IInvalidating IInvalidating obj validateNow setTypicalLayoutElement renderer super removeChild obj initializeTypicalItem 方法又调用 crteateItemRenderers 方法 private function createRendererForItem item Object failRTE Boolean true IVisualElement var myItemRenderer IVisualElement Rules for lookup 1 if itemRendererFunction is defined call it to get the renderer factory and instantiate it 2 if itemRenderer is defined instantiate one 3 if item is an IVisualElement and a DisplayObject use it directly 1 if itemRendererFunction is defined call it to get the renderer factory and instantiate it if itemRendererFunction null var rendererFactory IFactory itemRendererFunction item if the function returned a factory use that otherwise if it returned null try using the item directly if rendererFactory myItemRenderer rendererFactory newInstance else if item is IVisualElement 22 2 if itemRenderer is defined instantiate one if myItemRenderer 3 if item is an IVisualElement and a DisplayObject use it directly if myItemRenderer 上述方法中最终调用 itemRenderer newInstance 来通过 ClassFactory 实例化 MobileItemRenderer 类 即调用其构造器 itemRenderer 是 IFactory 类型 帮助创建指定类的实例 在 dataGroup 被加入到显示列表时 在 SkinnableDataContainer partAdded 方法中对 itemRenderer 进行了赋值 为了更加清晰 我们列出 ClassFactory 类的构造器和 newInstance 方法如下 ClassFactory 的构造器如下 public function ClassFactory generator Class null super this generator generator ClassFactory 的 newInstance 方法如下 public function newInstance var instance Object new generator if properties null for var p String in properties instance p properties p 23 return instance 上述代码中 调用 new generator 时 在本例中 即会调用 MobileItemRenderer 构造器开始 Component 类的初始化构造 2 Component 类初始化 Component 类 MobileItemRenderer 的构造器方法如下 public function MobileItemRenderer super setStyle skinClass com mark demos skins MobileItemSkin MobileItemRenderer 做了两件事 super 了一下 然后使用 setStyle 设定了他的 Skin 类 我们先看 super MobileItemRenderer 的父类是 SkinnableComponent 而 SkinnableComponent 继承了 U

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论