AS3开发人员指南


ACTIONSCRIPT® 3.0 开发人员指南上次更新 2014/12/1 法律声明 法律声明 有关法律声明,请参阅 http://help.adobe.com/zh_CN/legalnotices/index.html。iii 上次更新 2014/12/1 目录 第 1 章 : 使用日期和时间 管理日历日期和时间 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 控制时间间隔 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 日期和时间示例:简单模拟时钟 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 第 2 章 : 使用字符串 字符串基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 创建字符串 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 length 属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 处理字符串中的字符 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 比较字符串 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 获取其他对象的字符串表示形式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 连接字符串 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 在字符串中查找子字符串和模式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 转换字符串的大小写 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 字符串示例:ASCII 图表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 第 3 章 : 使用数组 数组基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 索引数组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 关联数组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 多维数组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 克隆数组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 扩展 Array 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 数组示例:播放列表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 第 4 章 : 处理错误 错误处理基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 错误类型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 ActionScript 3.0 中的错误处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 使用 Flash 运行时的调试版 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 在应用程序中处理同步错误 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 创建自定义错误类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 响应错误事件和状态 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 比较错误类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 处理错误示例:CustomErrors 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 第 5 章 : 使用正则表达式 正则表达式基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 正则表达式语法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64ivACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 对字符串使用正则表达式的方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 正则表达式示例:Wiki 解析程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 第 6 章 : 使用 XML XML 基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 用于处理 XML 的 E4X 方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 XML 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 XMLList 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 初始化 XML 变量 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 组合和变换 XML 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 遍历 XML 结构 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 使用 XML 命名空间 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 XML 类型转换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 读取外部 XML 文档 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 在 ActionScript 中使用 XML 的示例:从 Internet 加载 RSS 数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 第 7 章 : 使用本机 JSON 功能 JSON API 概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 定义自定义 JSON 行为 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 第 8 章 : 处理事件 事件处理基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 ActionScript 3.0 事件处理与早期版本事件处理的不同之处 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 事件流 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 事件对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 事件侦听器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 事件处理示例:闹钟 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 第 9 章 : 使用应用程序域 第 10 章 : 显示编程 显示编程的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 核心显示类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 显示列表方法的优点 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 使用显示对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 处理显示对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 对象动画 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 舞台方向 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 动态加载显示内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 显示对象示例:SpriteArranger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 第 11 章 : 使用几何结构 几何结构基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 使用 Point 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176vACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 使用 Rectangle 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 使用 Matrix 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 几何形状示例:对显示对象应用矩阵转换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 第 12 章 : 使用绘图 API 绘制 API 的基础 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Graphics 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 绘制线条和曲线 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 使用内置方法绘制形状 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 创建渐变线条和填充 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 将 Math 类与绘制方法配合使用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 使用绘图 API 进行动画处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 绘制 API 示例:算法可视化生成器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 绘图 API 高级用法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 第 13 章 : 使用位图 位图使用基本知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 Bitmap 和 BitmapData 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 处理像素 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 复制位图数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 压缩位图数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 使用杂点功能制作纹理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 滚动位图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 利用 mipmap 处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 位图示例:带动画效果的旋转的月亮 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 位图图像的异步解码 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 第 14 章 : 过滤显示对象 过滤显示对象的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 创建和应用滤镜 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 可用的显示滤镜 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 筛选显示对象示例:Filter Workbench . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 第 15 章 : 使用 Pixel Bender 着色器 Pixel Bender 着色器基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 加载或嵌入着色器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 访问着色器元数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 指定着色器输入和参数值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 使用着色器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 第 16 章 : 使用影片剪辑 影片剪辑基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 使用 MovieClip 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 控制影片剪辑播放 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271viACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 使用 ActionScript 创建 MovieClip 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 加载外部 SWF 文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 影片剪辑示例:RuntimeAssetsExplorer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 第 17 章 : 使用补间动画 补间动画基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 在 Flash 中复制补间动画脚本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 合并补间动画脚本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 描述动画 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 添加滤镜 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 将补间动画与其显示对象关联 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 第 18 章 : 使用反向运动 反向运动的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 IK 骨架动画处理概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 获取有关 IK 骨架的信息 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 实例化 IKMover 并限制其移动 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 移动 IK 骨架 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 使用弹簧 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 使用 IK 事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 第 19 章 : 在三维 (3D) 环境中工作 3D 显示对象的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 了解 Flash Player 和 AIR 运行时中的 3D 显示对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295 创建和移动 3D 显示对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 将 3D 对象投影到 2D 视图上 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 示例:透视投影 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 执行复杂的 3D 转换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 通过三角形获得 3D 效果 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 第 20 章 : 文本使用基础知识 第 21 章 : 使用 TextField 类 显示文本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 选择和操作文本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 捕获文本输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 限制文本输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 设置文本格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 高级文本呈现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322 使用静态文本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 TextField 示例:报纸风格的文本格式设置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325viiACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 第 22 章 : 使用 Flash 文本引擎 创建和显示文本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 处理 FTE 中的事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 设置文本格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 使用字体 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345 控制文本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 Flash 文本引擎示例:新闻版面布局 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 第 23 章 : 使用 Text Layout Framework Text Layout Framework 概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 使用 Text Layout Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 使用 TLF 构建文本结构 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 使用 TLF 设置文本格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369 使用 TLF 导入和导出文本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370 使用 TLF 管理文本容器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370 使用 TLF 启用文本选择、编辑和撤消 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 使用 TLF 处理事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 在文本内定位图像 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 第 24 章 : 处理声音 声音处理基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373 了解声音体系结构 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374 加载外部声音文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 处理嵌入的声音 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 处理声音流文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378 处理动态生成的音频 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 播放声音 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 加载和播放声音时的安全注意事项 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 控制音量和声相 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 处理声音元数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 访问原始声音数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 捕获声音输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 声音示例:Podcast Player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 第 25 章 : 使用视频 视频基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 了解视频格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 了解 Video 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 加载视频文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 控制视频播放 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 在全屏模式下播放视频 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 流式传输视频文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 了解提示点 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411viiiACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 编写元数据和提示点的回调方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 使用提示点和元数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416 监控 NetStream 活动 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 视频文件的高级主题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428 视频示例:视频自动唱片点唱机 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429 使用 StageVideo 类来实现硬件加速呈现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 第 26 章 : 使用摄像头 了解 Camera 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 在屏幕上显示摄像头内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 设计摄像头应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 连接至用户的摄像头 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 验证是否已安装摄像头 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 检测摄像头的访问权限 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 最优化摄像头视频品质 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 监控摄像头状态 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 第 27 章 : 使用数字权限管理 了解受保护的内容工作流程 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 NetStream 类中与 DRM 相关的成员和事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 使用 DRMStatusEvent 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456 使用 DRMAuthenticateEvent 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 使用 DRMErrorEvent 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 使用 DRMManager 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 使用 DRMContentData 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 更新 Flash Player 以支持 Adobe Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 带外许可证 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 域支持 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 使用域支持播放加密的内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 许可证预览 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 提交内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 Open Source Media Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 第 28 章 : 在 AIR 中添加 PDF 内容 检测 PDF 功能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469 加载 PDF 内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 编写 PDF 内容的脚本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 对 AIR 中的 PDF 内容的已知限制 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472 第 29 章 : 用户交互的基础知识 捕获用户输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 管理焦点 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 了解输入类型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475ixACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 第 30 章 : 键盘输入 捕获键盘输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477 使用 IME 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479 虚拟键盘 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483 第 31 章 : 鼠标输入 捕获鼠标输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 鼠标输入示例:WordSearch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492 第 32 章 : 触摸、多点触控和手势输入 触摸输入的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496 触摸支持发现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498 Touch 事件处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499 触摸和拖动 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 Gesture 事件处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503 疑难解答 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 第 33 章 : 复制和粘贴 复制粘贴基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 读取和写入系统剪贴板 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 AIR 中的 HTML 复制和粘贴 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 剪贴板数据格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512 第 34 章 : 加速计输入 检查加速计支持 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 检测加速计更改 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 第 35 章 : AIR 中的拖放 AIR 中拖放的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 支持拖出手势 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 支持拖入手势 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523 HTML 中的拖放 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525 将数据拖出 HTML 元素 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 将数据拖入 HTML 元素 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529 示例:覆盖默认的 HTML 拖入行为 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529 在非应用程序 HTML 沙箱中处理文件放置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 放置文件释放 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 第 36 章 : 使用菜单 菜单基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 创建本机菜单 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 关于 HTML 中的上下文菜单 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548 显示弹出本机菜单 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549xACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 处理菜单事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549 本机菜单示例:窗口和应用程序菜单 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551 第 37 章 : AIR 中的任务栏图标 关于任务栏图标 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554 停靠栏图标 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554 系统任务栏图标 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555 Window 任务栏图标和按钮 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 第 38 章 : 使用文件系统 使用 FileReference 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559 使用 AIR 文件系统 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571 第 39 章 : 存储本地数据 共享对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602 加密的本地存储区 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610 第 40 章 : 在 AIR 中使用本地 SQL 数据库 关于本地 SQL 数据库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613 创建和修改数据库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 操作 SQL 数据库数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 622 使用同步和异步数据库操作 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645 对 SQL 数据库使用加密 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649 使用 SQL 数据库的策略 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664 第 41 章 : 使用字节数组 读取并写入 ByteArray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666 ByteArray 示例:读取 .zip 文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671 第 42 章 : 网络和通信基础知识 网络接口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677 网络连接更改 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678 域名系统 (DNS) 记录 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681 第 43 章 : 套接字 TCP 套接字 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683 UDP 套接字 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693 IPv6 地址 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694 第 44 章 : HTTP 通信 加载外部数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696 Web 服务请求 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703 在其他应用程序中打开 URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 710xiACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 第 45 章 : 与其他 Flash Player 和 AIR 实例通信 关于 LocalConnection 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712 在两个应用程序之间发送消息 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 714 连接到不同域中的内容和 AIR 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715 第 46 章 : 与 AIR 中的本机进程通信 本机进程通信概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 717 启动和关闭本机进程 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 718 与本机进程通信 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 718 本机进程通信的安全性注意事项 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720 第 47 章 : 使用外部 API 使用外部 API 的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721 外部 API 要求和优点 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 723 使用 ExternalInterface 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724 外部 API 示例:在 ActionScript 和 Web 浏览器中的 JavaScript 之间进行通信 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727 第 48 章 : AIR 中的 XML 签名验证 XML 签名验证的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733 关于 XML 签名 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736 实现 IURIDereferencer 接口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738 第 49 章 : 客户端系统环境 客户端系统环境基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 使用 System 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 使用 Capabilities 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 747 功能示例:检测系统功能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 747 第 50 章 : AIR 应用程序的调用和终止 应用程序调用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751 捕获命令行参数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752 用户登录时调用 AIR 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 755 从浏览器调用 AIR 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 756 应用程序终止 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757 第 51 章 : 处理 AIR 运行时和操作系统信息 管理文件关联 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 759 获取运行时版本和修补级别 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 759 检测 AIR 功能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760 跟踪用户当前状态 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760 第 52 章 : 使用 AIR 本机窗口 AIR 中的本机窗口的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 761 创建窗口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 767 管理窗口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775xiiACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 侦听窗口事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782 显示全屏窗口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783 第 53 章 : AIR 中的显示屏幕 AIR 中的显示屏幕的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 785 枚举屏幕 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 786 第 54 章 : 打印 打印基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 789 打印页面 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 789 Flash 运行时任务和系统打印 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 790 设置大小、缩放和方向 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 792 高级打印技术 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794 打印示例:多页面打印 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796 打印示例:缩放、裁剪和响应 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798 打印示例:页面设置和打印选项 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 799 第 55 章 : Geolocation 检测 geolocation 更改 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802 第 56 章 : 应用程序国际化 应用程序国际化基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 805 flash.globalization 包概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806 确定区域设置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807 设置数字格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808 设置货币值格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 810 设置日期和时间格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 812 排序和比较字符串 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813 大小写转换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814 示例:国际化股票报价应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 815 第 57 章 : 本地化应用程序 选择区域设置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 819 本地化 Flex 内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 819 本地化 Flash 内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 820 本地化 AIR 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 820 对日期、时间和货币进行本地化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 820 第 58 章 : 关于 HTML 环境 HTML 环境概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 823 AIR 和 WebKit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825 第 59 章 : 在 AIR 中进行 HTML 和 JavaScript 编程 关于 HTMLLoader 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839 避免与安全相关的 JavaScript 错误 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841xiiiACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 通过 JavaScript 访问 AIR API 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 845 关于 AIR 中的 URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 846 使 ActionScript 对象可用于 JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847 从 ActionScript 访问 HTML DOM 和 JavaScript 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 848 在 HTML 中嵌入 SWF 内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 849 在 HTML 页中使用 ActionScript 库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 852 转换 Date 和 RegExp 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 853 从 ActionScript 操作 HTML 样式表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 跨脚本访问不同安全沙箱中的内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 855 第 60 章 : 为 AIR HTML 容器编写脚本 HTMLLoader 对象的显示属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859 滚动 HTML 内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861 访问 HTML 历史记录列表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862 设置在加载 HTML 内容时使用的用户代理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 设置用于 HTML 内容的字符编码 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 为 HTML 内容定义类似于浏览器的用户界面 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 创建 HTMLLoader 类的子类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 872 第 61 章 : 处理 AIR 中与 HTML 相关的事件 HTMLLoader 事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874 使用 ActionScript 处理 DOM 事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874 响应未捕获的 JavaScript 异常 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 875 使用 JavaScript 处理运行时事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 877 第 62 章 : 在移动应用程序中显示 HTML 内容 StageWebView 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880 内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880 导航事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 882 历史记录 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 883 焦点 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884 位图捕获 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886 第 63 章 : 将 worker 用于并发 了解 worker 与并发 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 888 创建和管理 worker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 889 在 worker 之间进行通信 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 891 第 64 章 : 安全性 Flash Platform 安全概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894 安全沙箱 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 权限控制 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899 限制网络 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905 全屏模式安全性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907xivACTIONSCRIPT 3.0 开发人员指南 目录 上次更新 2014/12/1 全屏交互模式安全性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908 加载内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908 跨脚本访问 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 911 作为数据访问加载的媒体 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 913 加载数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915 从导入到安全域的 SWF 文件加载嵌入内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 使用旧内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 设置 LocalConnection 权限 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919 控制外出 URL 访问 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919 共享对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 920 摄像头、麦克风、剪贴板、鼠标和键盘访问 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921 AIR 安全性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 922 第 65 章 : 如何使用 ActionScript 示例 示例类型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939 在 Flash Professional 中运行 ActionScript 3.0 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 940 在 Flash Builder 中运行 ActionScript 3.0 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 942 在移动设备上运行 ActionScript 3.0 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 943 第 66 章 : 本地数据库中的 SQL 支持 支持的 SQL 语法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 946 数据类型支持 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 963 第 67 章 : SQL 错误详细消息、 ID 和参数 第 68 章 : Adobe 图形汇编语言 (AGAL) AGAL 字节码格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9701 上次更新 2014/12/1 第 1 章 : 使用日期和时间 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 时间可能并不代表一切,但它在软件应用程序中通常是一个关键要素。 ActionScript 3.0 提供了多种强大的手段来管理日历日 期、时间和时间间隔。以下两个主类提供了大部分的计时功能:Date 类和 flash.utils 包中的新 Timer 类。 日期和时间是在 ActionScript 程序中使用的一种常见信息类型。例如,您可能需要了解当前星期值,或测量用户在特定屏幕 上花费多少时间,并且还可能会执行很多其他操作。在 ActionScript 中,可以使用 Date 类来表示某一时刻,其中包含日期和 时间信息。 Date 实例中包含各个日期和时间单位的值,其中包括年、月、日、星期、小时、分钟、秒、毫秒以及时区。对于更 高级的用法, ActionScript 还包括 Timer 类,您可以使用该类在一定延迟后执行动作,或按重复间隔执行动作。 更多帮助主题 Date flash.utils.Timer 管理日历日期和时间 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 的所有日历日期和时间管理函数都集中在顶级 Date 类中。Date 类包含一些方法和属性,这些方法和属性能 够使您按照通用协调时间 (UTC) 或特定于时区的本地时间来处理日期和时间。UTC 是一种标准时间定义,它实质上与格林尼 治标准时间 (GMT) 相同。 创建 Date 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Date 类是所有核心类中构造函数方法形式最为多变的类之一。您可以用以下四种方式来调用 Date 类。 第一,如果未给定参数,则 Date() 构造函数将按照您所在时区的本地时间返回包含当前日期和时间的 Date 对象。这里提供了 一个示例: var now:Date = new Date(); 第二,如果仅给定了一个数字参数,则 Date() 构造函数将其视为自 1970 年 1 月 1 日以来经过的毫秒数,并且返回对应的 Date 对象。请注意,您传入的毫秒值将被视为自 1970 年 1 月 1 日(UTC 时间)以来经过的毫秒数。但是,该 Date 对象会按照您 所在的本地时区来显示值,除非您使用特定于 UTC 的方法来检索和显示这些值。如果仅使用一个毫秒参数来创建新的 Date 对 象,则应确保考虑到您的当地时间和 UTC 之间的时区差异。以下语句创建一个设置为 1970 年 1 月 1 日午夜(UTC 时间)的 Date 对象: var millisecondsPerDay:int = 1000 * 60 * 60 * 24; // gets a Date one day after the start date of 1/1/1970 var startTime:Date = new Date(millisecondsPerDay); 第三,您可以将多个数值参数传递给 Date() 构造函数。该构造函数将这些参数分别视为年、月、日、小时、分钟、秒和毫秒, 并将返回一个对应的 Date 对象。假定这些输入参数采用的是本地时间而不是 UTC。以下语句获取一个设置为 2000 年 1 月 1 日开始的午夜 (本地时间)的 Date 对象: var millenium:Date = new Date(2000, 0, 1, 0, 0, 0, 0);2ACTIONSCRIPT 3.0 开发人员指南 使用日期和时间 上次更新 2014/12/1 第四,您可以将单个字符串参数传递给 Date() 构造函数。该构造函数将尝试把字符串分析为日期或时间部分,然后返回对应的 Date 对象。如果使用此方法,最好将 Date() 构造函数包含在 try..catch 块中,以捕获所有分析错误。 Date() 构造函数可接受多 种不同的字符串格式 (用于 Adobe Flash Platform 的 ActionScript 3.0 参考中列出了这些格式)。以下语句使用字符串值初 始化一个新的 Date 对象: var nextDay:Date = new Date("Mon May 1 2006 11:30:00 AM"); 如果 Date() 构造函数无法成功分析该字符串参数,它不会引发异常。但是,所得到的 Date 对象将包含一个无效的日期值。 获取时间单位值 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 Date 类的属性或方法从 Date 对象中提取各种时间单位的值。下面的每个属性为您提供了 Date 对象中的一个时间单 位的值: • fullYear 属性 • month 属性,以数字格式表示,分别以 0 到 11 表示一月到十二月 • date 属性,表示月中某一天的日历数字,范围为 1 到 31 • day 属性,以数字格式表示一周中的某一天,其中 0 表示星期日 • hours 属性,范围为 0 到 23 • minutes 属性 • seconds 属性 • milliseconds 属性 实际上, Date 类为您提供了获取这些值的多种方式。例如,您可以用四种不同方式获取 Date 对象的月份值: • month 属性 • getMonth() 方法 • monthUTC 属性 • getMonthUTC() 方法 所有四种方式实质上具有同等的效率,因此您可以任意使用一种最适合应用程序的方法。 刚才列出的属性表示总日期值的各个部分。例如,milliseconds 属性永远不会大于 999,因为当它达到 1000 时,秒钟值就 会增加 1 并且 milliseconds 属性会重置为 0。 如果要获取 Date 对象自 1970 年 1 月 1 日 (UTC) 起所经过毫秒数的值,可以使用 getTime() 方法。通过使用与其相对应的 setTime() 方法,可以使用自 1970 年 1 月 1 日 (UTC) 起所经过的毫秒数更改现有 Date 对象的值。 执行日期和时间运算 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 您可以使用 Date 类对日期和时间执行加法和减法运算。日期值在内部以毫秒的形式保存,因此您应将其他值转换成毫秒,然 后再将它们与 Date 对象进行加减。 如果应用程序将执行大量的日期和时间运算,您可能会发现创建常量来保存常见时间单位值 (以毫秒的形式)非常有用,如下 所示: public static const millisecondsPerMinute:int = 1000 * 60; public static const millisecondsPerHour:int = 1000 * 60 * 60; public static const millisecondsPerDay:int = 1000 * 60 * 60 * 24;3ACTIONSCRIPT 3.0 开发人员指南 使用日期和时间 上次更新 2014/12/1 现在,可以方便地使用标准时间单位来执行日期运算。下列代码使用 getTime() 和 setTime() 方法将日期值设置为当前时间一个 小时后的时间: var oneHourFromNow:Date = new Date(); oneHourFromNow.setTime(oneHourFromNow.getTime() + millisecondsPerHour); 设置日期值的另一种方式是仅使用一个毫秒参数创建新的 Date 对象。例如,下列代码将一个日期加上 30 天以计算另一个日 期: // sets the invoice date to today's date var invoiceDate:Date = new Date(); // adds 30 days to get the due date var dueDate:Date = new Date(invoiceDate.getTime() + (30 * millisecondsPerDay)); 接着,将 millisecondsPerDay 常量乘以 30 以表示 30 天的时间,将结果与 invoiceDate 值相加,用于设置 dueDate 值。 在时区之间进行转换 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在需要将日期从一种时区转换成另一种时区时,使用日期和时间运算十分方便。也可以使用 getTimezoneOffset() 方法,该方法 返回的值表示 Date 对象的时区与 UTC 之间相差的分钟数。此方法之所以返回以分钟为单位的值,是因为并不是所有时区之间 都正好相差一个小时,有些时区与邻近的时区仅相差半个小时。 以下示例使用时区偏移量将日期从本地时间转换成 UTC。该示例首先以毫秒为单位计算时区值,然后按照该量调整 Date 值: // creates a Date in local time var nextDay:Date = new Date("Mon May 1 2006 11:30:00 AM"); // converts the Date to UTC by adding or subtracting the time zone offset var offsetMilliseconds:Number = nextDay.getTimezoneOffset() * 60 * 1000; nextDay.setTime(nextDay.getTime() + offsetMilliseconds); 控制时间间隔 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用 Adobe Flash CS4 Professional 开发应用程序时,您可以访问时间轴,这会使您稳定且逐帧地完成该应用程序。但在纯 ActionScript 项目中,您必须依靠其他计时机制。 循环与计时器之比较 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在某些编程语言中,必须使用循环语句 (如 for 或 do..while)来设计自己的计时方案 while. 通常,循环语句会以本地计算机所允许的速度尽可能快地执行,这表明应用程序在某些计算机上的运行速度较快而在其他计算 机上则较慢。如果应用程序需要一致的计时间隔,则您需要将其与实际的日历或时钟时间联系在一起。许多应用程序 (如游 戏、动画和实时控制器)需要在不同计算机上均能保持一致的、规则的时间驱动计时机制。 ActionScript 3.0 的 Timer 类提供了一个功能强大的解决方案。使用 ActionScript 3.0 事件模型, Timer 类在每次达到指定 的时间间隔时都会调度计时器事件。4ACTIONSCRIPT 3.0 开发人员指南 使用日期和时间 上次更新 2014/12/1 Timer 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 3.0 中处理计时函数的首选方式是使用 Timer 类 (flash.utils.Timer),可以使用它在每次达到间隔时调度事 件。 要启动计时器,请先创建 Timer 类的实例,并告诉它每隔多长时间生成一次计时器事件以及在停止前生成多少次事件。 例如,下列代码创建一个每秒调度一个事件且持续 60 秒的 Timer 实例: var oneMinuteTimer:Timer = new Timer(1000, 60); Timer 对象在每次达到指定的间隔时都会调度 TimerEvent 对象。 TimerEvent 对象的事件类型是 timer (由常量 TimerEvent.TIMER 定义)。 TimerEvent 对象包含的属性与标准 Event 对象包含的属性相同。 如果将 Timer 实例设置为固定的间隔数,则在达到最后一次间隔时,它还会调度 timerComplete 事件 (由常量 TimerEvent.TIMER_COMPLETE 定义)。 以下是一个用来展示 Timer 类实际操作的小示例应用程序: package { import flash.display.Sprite; import flash.events.TimerEvent; import flash.utils.Timer; public class ShortTimer extends Sprite { public function ShortTimer() { // creates a new five-second Timer var minuteTimer:Timer = new Timer(1000, 5); // designates listeners for the interval and completion events minuteTimer.addEventListener(TimerEvent.TIMER, onTick); minuteTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete); // starts the timer ticking minuteTimer.start(); } public function onTick(event:TimerEvent):void { // displays the tick count so far // The target of this event is the Timer instance itself. trace("tick " + event.target.currentCount); } public function onTimerComplete(event:TimerEvent):void { trace("Time's Up!"); } } } 创建 ShortTimer 类时,它会创建一个用于每秒计时一次并持续五秒的 Timer 实例。然后,它将两个侦听器添加到计时器:一 个用于侦听每次计时,另一个用于侦听 timerComplete 事件。 接着,它启动计数器计时,并且从此时起以一秒钟的间隔执行 onTick() 方法。 onTick() 方法只显示当前的时间计数。五秒钟后,执行 onTimerComplete() 方法,告诉您时间已到。 运行该示例时,您应会看到下列行以每秒一行的速度显示在控制台或跟踪窗口中:5ACTIONSCRIPT 3.0 开发人员指南 使用日期和时间 上次更新 2014/12/1 tick 1 tick 2 tick 3 tick 4 tick 5 Time's Up! flash.utils 包中的计时函数 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 包含许多与 ActionScript 2.0 提供的计时函数类似的计时函数。这些函数是作为 flash.utils 包中的包级别函 数提供的,它们的功能与 ActionScript 2.0 中完全相同。 这些函数仍保留在 ActionScript 3.0 以实现向后兼容。 Adobe 不建议您在新的 ActionScript 3.0 应用程序中使用这些函数。 通常,在应用程序中使用 Timer 类会更容易且更有效。 日期和时间示例:简单模拟时钟 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 简单的模拟时钟示例说明了这两个日期和时间概念: • 获取当前日期和时间并提取小时、分钟和秒的值 • 使用 Timer 设置应用程序的运行速度 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在 Samples/SimpleClock 文件夹中找到 SimpleClock 应用程序文件。该应用程序包含以下文件: 函数 说明 clearInterval(id:uint):void 取消指定的 setInterval() 调用。 clearTimeout(id:uint):void 取消指定的 setTimeout() 调用。 getTimer():int 返回自 Adobe® Flash® Player 或 Adobe® AIR™ 初始化以来经过的毫秒数。 setInterval(closure:Function, delay:Number, ... arguments):uint 以指定的间隔 (以毫秒为单位)运行函数。 setTimeout(closure:Function, delay:Number, ... arguments):uint 在指定的延迟 (毫秒)后运行指定的函数。 文件 说明 SimpleClockApp.mxml 或 SimpleClockApp.fla Flash 或 Flex 中的主应用程序文件 (分别为 FLA 和 MXML)。 com/example/programmingas3/simpleclock/SimpleClock.as 主应用程序文件。 com/example/programmingas3/simpleclock/AnalogClockFace.as 根据时间绘制一个圆形的钟面以及时针、分针和秒针。6ACTIONSCRIPT 3.0 开发人员指南 使用日期和时间 上次更新 2014/12/1 定义 SimpleClock 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 此时钟示例很简单,但是将即使很简单的应用程序也组织得十分有条理是一种很好的做法,以便您将来能够很轻松地扩展这些 应用程序。为此, SimpleClock 应用程序使用 SimpleClock 类处理启动和时间保持任务,然后使用另一个名称为 AnalogClockFace 的类来实际显示该时间。 以下代码用于定义和初始化 SimpleClock 类 (请注意,在 Flash 版本中, SimpleClock 扩展了 Sprite 类): public class SimpleClock extends UIComponent { /** * The time display component. */ private var face:AnalogClockFace; /** * The Timer that acts like a heartbeat for the application. */ private var ticker:Timer; 该类具有两个重要的属性: • face 属性,它是 AnalogClockFace 类的实例 • ticker 属性,它是 Timer 类的实例 SimpleClock 类使用默认构造函数。 initClock() 方法处理实际的设置工作,它创建钟面并启动 Timer 实例的计时。 创建钟面 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 SimpleClock 代码中后面的几行代码创建用于显示时间的钟面: /** * Sets up a SimpleClock instance. */ public function initClock(faceSize:Number = 200) { // creates the clock face and adds it to the display list face = new AnalogClockFace(Math.max(20, faceSize)); face.init(); addChild(face); // draws the initial clock display face.draw(); 可以将钟面的大小传递给 initClock() 方法。如果未传递 faceSize 值,则使用 200 个像素的默认大小。 接着,应用程序将钟面初始化,然后使用从 DisplayObjectContainer 类继承的 addChild() 方法将该钟面添加到显示列表。然 后,它调用 AnalogClockFace.draw() 方法显示一次钟面,同时显示当前时间。 启动计时器 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 创建钟面后, initClock() 方法会设置一个计时器: 7ACTIONSCRIPT 3.0 开发人员指南 使用日期和时间 上次更新 2014/12/1 // creates a Timer that fires an event once per second ticker = new Timer(1000); // designates the onTick() method to handle Timer events ticker.addEventListener(TimerEvent.TIMER, onTick); // starts the clock ticking ticker.start(); 首先,该方法初始化一个每秒 (每隔 1000 毫秒)调度一次事件的 Timer 实例。由于没有向 Timer() 构造函数传递第二个 repeatCount 参数,因此 Timer 将无限期地重复计时。 SimpleClock.onTick() 方法将在每秒收到 timer 事件时执行一次。 public function onTick(event:TimerEvent):void { // updates the clock display face.draw(); } AnalogClockFace.draw() 方法仅绘制钟面和指针。 显示当前时间 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 AnalogClockFace 类中大多数代码都与设置钟面的显示元素有关。 AnalogClockFace 在进行初始化时,会绘制一个圆形轮 廓,将数字文本标签放在每个小时刻度处,然后创建三个 Shape 对象,分别表示时钟的时针、分针和秒针。 在 SimpleClock 应用程序运行后,它会每秒调用一次 AnalogClockFace.draw() 方法,如下所示: /** * Called by the parent container when the display is being drawn. */ public override function draw():void { // stores the current date and time in an instance variable currentTime = new Date(); showTime(currentTime); } 此方法将当前时间保存在变量中,因此在绘制时钟指针的过程中无法改变时间。然后,调用 showTime() 方法以显示指针,如 下所示:8ACTIONSCRIPT 3.0 开发人员指南 使用日期和时间 上次更新 2014/12/1 /** * Displays the given Date/Time in that good old analog clock style. */ public function showTime(time:Date):void { // gets the time values var seconds:uint = time.getSeconds(); var minutes:uint = time.getMinutes(); var hours:uint = time.getHours(); // multiplies by 6 to get degrees this.secondHand.rotation = 180 + (seconds * 6); this.minuteHand.rotation = 180 + (minutes * 6); // Multiply by 30 to get basic degrees, then // add up to 29.5 degrees (59 * 0.5) // to account for the minutes. this.hourHand.rotation = 180 + (hours * 30) + (minutes * 0.5); } 首先,此方法提取当前时间的小时、分钟和秒的值。然后使用这些值来计算每个指针的角度。由于秒针会在 60 秒内旋转一圈, 因此它每秒都会旋转 6 度 (360/60)。分针每分钟都旋转同样的度数。 时针每分钟都在更新,因此时针能够随着分针的跳动显示出某些时间变化过程。时针每小时旋转 30 度 (360/12),但也会每分 钟旋转半度 (30 度除以 60 分钟)。 9 上次更新 2014/12/1 第 2 章 : 使用字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 String 类包含使您能够使用文本字符串的方法。在使用许多对象时,字符串都十分重要。此处介绍的这些方法对使用在对象中 (如 TextField、 StaticText、 XML、 ContextMenu 和 FileReference 对象)使用的字符串很有帮助。 字符串是字符的序列。 ActionScript 3.0 支持 ASCII 字符和 Unicode 字符。 更多帮助主题 String RegExp parseFloat() parseInt() 字符串基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在编程语言中,字符串是指一个文本值,即串在一起而组成单个值的一系列字母、数字或其他字符。例如,以下一行代码创建 一个数据类型为 String 的变量,并为该变量赋予一个文本字符串值: var albumName:String = "Three for the money"; 正如此示例所示,在 ActionScript 中,可使用双引号或单引号将本文引起来以表示字符串值。以下是另外几个字符串示例: "Hello" "555-7649" "http://www.adobe.com/" 每当在 ActionScript 中使用一段文本时,您都会用到字符串值。 ActionScript String 类是一种可用来使用文本值的数据类 型。 String 实例通常用于很多其他 ActionScript 类中的属性、方法参数等。 重要概念和术语 以下参考列表包含您会遇到的与字符串有关的重要术语: ASCII 在计算机程序中用于表示文本字符和符号的系统。 ASCII 系统支持 26 个字母英文字母表,以及有限的一组其他字符。 字符 文本数据的最小单位 (单个字母或符号)。 连接 通过将一个字符串值添加到其他字符串值的末端,将多个字符串值连接到一起,从而创建新的字符串值。 空字符串 不包含文本、空白或其他字符的字符串,可以写为 ""。空字符串值不同于具有 null 值的 String 变量;值为 null 的 String 变量是指没有赋予 String 实例的变量,而空字符串则包含一个实例,其值不包含任何字符。 String 文本值 (字符序列)。 字符串文本 (或 “ 文本字符串 ”) 在代码中明确编写的字符串值,书写方式为由双引号或单一引号括起来的文本值。 子字符串 作为其他字符串一部分的字符串。 Unicode 在计算机程序中用于表示文本字符和符号的标准系统。 Unicode 系统允许使用任何编写系统中的任何字符。10ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 创建字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 3.0 中, String 类用于表示字符串 (文本)数据。 ActionScript 字符串支持 ASCII 字符和 Unicode 字符。 创建字符串的最简单方式是使用字符串文本。要声明字符串文本,请使用双直引号 (") 或单直引号 (') 字符。例如,以下两个字 符串是等效的: var str1:String = "hello"; var str2:String = 'hello'; 您还可以使用 new 运算符来声明字符串,如下所示: var str1:String = new String("hello"); var str2:String = new String(str1); var str3:String = new String(); // str3 == "" 下面的两个字符串是等效的: var str1:String = "hello"; var str2:String = new String("hello"); 若要在使用单引号 (') 分隔符定义的字符串文本内使用单引号 ('),请使用反斜杠转义符 (\)。类似地,要在使用双引号 (") 分隔 符定义的字符串文本内使用双引号 ("),请使用反斜杠转义符 (\)。下面的两个字符串是等效的: var str1:String = "That's \"A-OK\""; var str2:String = 'That\'s "A-OK"'; 您可以根据字符串文本中存在的任何单引号或双引号来选择使用单引号或双引号,如下所示: var str1:String = "ActionScript 3.0"; var str2:String = 'banana'; 请务必记住 ActionScript 可区分单直引号 (') 和左右单引号 (' 或 ')。对于双引号也同样如此。请使用直引号来分割字符串文本。 在将文本从其他来源粘贴到 ActionScript 中时,请确保使用正确的字符。 如下表所示,可以使用反斜杠转义符 (\) 在字符串文本中定义其他字符: 转义序列 字符 \b Backspace \f 换页符 \n 换行符 \r 回车符 \t Tab \unnnn Unicode 字符,字符代码由十六进制数字 nnnn 指定;例如, \u263a 为笑脸字符。 \\xnn ASCII 字符,字符代码由十六进制数字 nn 指定。 \' 单引号 \" 双引号 \\ 单个反斜杠字符11ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 length 属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 每个字符串都有 length 属性,其值等于字符串中的字符数: var str:String = "Adobe"; trace(str.length); // output: 5 空字符串和 null 字符串的长度均为 0,如下例所示: var str1:String = new String(); trace(str1.length); // output: 0 str2:String = ''; trace(str2.length); // output: 0 处理字符串中的字符 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 字符串中的每个字符在字符串中都有一个索引位置 (整数)。第一个字符的索引位置为 0。例如,在下面的字符串中,字符 y 的位置为 0,而字符 w 的位置为 5: "yellow" 您可以使用 charAt() 方法和 charCodeAt() 方法检查字符串各个位置上的字符,如此示例所示: var str:String = "hello world!"; for (var i:int = 0; i < str.length; i++) { trace(str.charAt(i), "-", str.charCodeAt(i)); } 在运行此代码时,会产生如下输出: h - 104 e - 101 l - 108 l - 108 o - 111 - 32 w - 119 o - 111 r - 114 l - 108 d - 100 ! - 33 您还可以通过字符代码,使用 fromCharCode() 方法定义字符串,如下例所示: var myStr:String = String.fromCharCode(104,101,108,108,111,32,119,111,114,108,100,33); // Sets myStr to "hello world!"12ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 比较字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用以下运算符比较字符串:<、<=、!=、==、=> 和 >。可以将这些运算符用于条件语句(如 if 和 while),如下例所示: var str1:String = "Apple"; var str2:String = "apple"; if (str1 < str2) { trace("A < a, B < b, C < c, ..."); } 在将这些运算符用于字符串时, ActionScript 会使用字符串中每个字符的字符代码值从左到右比较各个字符,如下所示: trace("A" < "B"); // true trace("A" < "a"); // true trace("Ab" < "az"); // true trace("abc" < "abza"); // true 使用 == 和 != 运算符可比较两个字符串,也可以将字符串与其他类型的对象进行比较,如下例所示: var str1:String = "1"; var str1b:String = "1"; var str2:String = "2"; trace(str1 == str1b); // true trace(str1 == str2); // false var total:uint = 1; trace(str1 == total); // true 获取其他对象的字符串表示形式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以获取任何类型对象的字符串表示形式。所有对象都提供了 toString() 方法来实现此目的: var n:Number = 99.47; var str:String = n.toString(); // str == "99.47" 在使用 + 连接运算符连接 String 对象和不属于字符串的对象时,无需使用 toString() 方法。有关连接的详细信息,请参阅下一 节。 对于给定对象, String() 全局函数返回的值与调用该对象的 toString() 方法返回的值相同。 连接字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 字符串连接的含义是:将两个字符串按顺序合并为一个字符串。例如,可以使用 + 运算符来连接两个字符串: var str1:String = "green"; var str2:String = "ish"; var str3:String = str1 + str2; // str3 == "greenish" 还可以使用 += 运算符来得到相同的结果,如下例所示:13ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 var str:String = "green"; str += "ish"; // str == "greenish" 此外, String 类还包括 concat() 方法,可按如下方式对其进行使用: var str1:String = "Bonjour"; var str2:String = "from"; var str3:String = "Paris"; var str4:String = str1.concat(" ", str2, " ", str3); // str4 == "Bonjour from Paris" 如果使用 + 运算符 (或 += 运算符)对 String 对象和非 字符串的对象进行运算,则 ActionScript 会自动将非字符串对象转换 为 String 对象以计算该表达式,如下例所示: var str:String = "Area = "; var area:Number = Math.PI * Math.pow(3, 2); str = str + area; // str == "Area = 28.274333882308138" 但是,可以使用括号进行分组,为 + 运算符提供运算的上下文,如下例所示: trace("Total: $" + 4.55 + 1.45); // output: Total: $4.551.45 trace("Total: $" + (4.55 + 1.45)); // output: Total: $6 在字符串中查找子字符串和模式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 子字符串是字符串内的字符序列。例如,字符串 "abc" 具有如下子字符串:""、 "a"、 "ab"、 "abc"、 "b"、 "bc"、 "c"。可使用 ActionScript 的方法来查找字符串的子字符串。 模式是在 ActionScript 中通过字符串或正则表达式定义的。例如,下面的正则表达式定义了一个特定模式,即字母 A、B 和 C 的后面跟着一个数字字符 (正斜杠是正则表达式的分隔符): /ABC\d/ ActionScript 提供了在字符串中查找模式的方法,以及使用替换子字符串替换找到的匹配项的方法。随后的章节将介绍这些方 法。 正则表达式可定义十分复杂的模式。有关详细信息,请参阅第 63 页的 “ 使用正则表达式 ”。 通过字符位置查找子字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 substr() 和 substring() 方法非常类似。两个方法都返回字符串的一个子字符串。并且两个方法都具有两个参数。在这两个方法 中,第一个参数是给定字符串中起始字符的位置。不过,在 substr() 方法中,第二个参数是要返回的子字符串的长度,而在 substring() 方法中,第二个参数是子字符串的结尾 处字符的位置 (该字符未包含在返回的字符串中)。此示例显示了这两种方 法之间的差别: var str:String = "Hello from Paris, Texas!!!"; trace(str.substr(11,15)); // output: Paris, Texas!!! trace(str.substring(11,15)); // output: Pari slice() 方法与 substring() 方法的工作方式类似。当指定两个非负整数作为参数时,其运行方式将完全一样。但是, slice() 方法 可以使用负整数作为参数,此时字符位置将从字符串末尾开始向前算起,如下例所示:14ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 var str:String = "Hello from Paris, Texas!!!"; trace(str.slice(11,15)); // output: Pari trace(str.slice(-3,-1)); // output: !! trace(str.slice(-3,26)); // output: !!! trace(str.slice(-3,str.length)); // output: !!! trace(str.slice(-8,-3)); // output: Texas 可以结合使用非负整数和负整数作为 slice() 方法的参数。 查找匹配子字符串的字符位置 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 indexOf() 和 lastIndexOf() 方法在字符串内查找匹配的子字符串,如下例所示: var str:String = "The moon, the stars, the sea, the land"; trace(str.indexOf("the")); // output: 10 请注意, indexOf() 方法区分大小写。 可以指定第二个参数以指出在字符串中开始进行搜索的起始索引位置,如下所示: var str:String = "The moon, the stars, the sea, the land" trace(str.indexOf("the", 11)); // output: 21 lastIndexOf() 方法在字符串中查找子字符串的最后一个匹配项: var str:String = "The moon, the stars, the sea, the land" trace(str.lastIndexOf("the")); // output: 30 如果为 lastIndexOf() 方法提供了第二个参数,搜索将从字符串中的该索引位置反向 (从右到左)进行: var str:String = "The moon, the stars, the sea, the land" trace(str.lastIndexOf("the", 29)); // output: 21 创建由分隔符分隔的子字符串数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可使用 split() 方法创建子字符串数组,该数组根据分隔符进行划分。例如,可以将逗号分隔或制表符分隔的字符串分为多个字 符串。 以下示例说明如何使用 “ 与 ” 字符 (&) 作为分隔符,将数组分割为多个子字符串: var queryStr:String = "first=joe&last=cheng&title=manager&StartDate=3/6/65"; var params:Array = queryStr.split("&", 2); // params == ["first=joe","last=cheng"] split() 方法的第二个参数是可选参数,该参数定义所返回数组的最大大小。 此外,还可以使用正则表达式作为分隔符: var str:String = "Give me\t5." var a:Array = str.split(/\s+/); // a == ["Give","me","5."] 有关详细信息,请参阅第 63 页的 “ 使用正则表达式 ” 和用于 Adobe Flash Platform 的 ActionScript 3.0 参考。15ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 在字符串中查找模式并替换子字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 String 类提供了使用字符串中的模式的以下方法: • 使用 match() 和 search() 方法可查找与模式相匹配的子字符串。 • 使用 replace() 方法可查找与模式相匹配的子字符串并使用指定子字符串替换它们。 随后的章节将介绍这些方法。 您可以使用字符串或正则表达式定义在这些方法中使用的模式。有关正则表达式的详细信息,请参阅第 63 页的 “ 使用正则表 达式 ”。 查找匹配的子字符串 search() 方法返回与给定模式相匹配的第一个子字符串的索引位置,如下例所示: var str:String = "The more the merrier."; // (This search is case-sensitive.) trace(str.search("the")); // output: 9 您还可以使用正则表达式定义要匹配的模式,如下例所示: var pattern:RegExp = /the/i; var str:String = "The more the merrier."; trace(str.search(pattern)); // 0 trace() 方法的输出为 0,因为字符串中第一个字符的索引位置为 0。在正则表达式中设置了 i 标志,因此搜索时不区分大小写。 search() 方法仅查找一个匹配项并返回其起始索引位置,即便在正则表达式中设置了 g (全局)标志。 下例展示一个更复杂的正则表达式,该表达式匹配被双引号引起来的字符串: var pattern:RegExp = /"[^"]*"/; var str:String = "The \"more\" the merrier."; trace(str.search(pattern)); // output: 4 str = "The \"more the merrier."; trace(str.search(pattern)); // output: -1 // (Indicates no match, since there is no closing double quotation mark.) match() 方法的工作方式与此类似。它搜索一个匹配的子字符串。但是,如果在正则表达式模式中使用了全局标志 (如下例所 示), match() 将返回一个包含匹配子字符串的数组: var str:String = "bob@example.com, omar@example.org"; var pattern:RegExp = /\w*@\w*\.[org|com]+/g; var results:Array = str.match(pattern); 对 results 数组进行如下设置: ["bob@example.com","omar@example.org"] 有关正则表达式的详细信息,请参阅第 63 页的 “ 使用正则表达式 ”。 替换匹配的子字符串 您可以使用 replace() 方法在字符串中搜索指定模式并使用指定的替换字符串替换匹配项,如下例所示: var str:String = "She sells seashells by the seashore."; var pattern:RegExp = /sh/gi; trace(str.replace(pattern, "sch")); //sche sells seaschells by the seaschore. 请注意,在本例中,因为在正则表达式中设置了 i (ignoreCase) 标志,所以匹配的字符串是不区分大小写的;而且因为设置了 g (global) 标志,所以会替换多个匹配项。有关详细信息,请参阅第 63 页的 “ 使用正则表达式 ”。16ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 可以在替换字符串中包括以下 $ 替换代码。下表所示的替换文本将插入并替换 $ 替换代码: 例如,下面说明了如何使用 $2 和 $1 替换代码,它们分别表示匹配的第一个和第二个捕获组: var str:String = "flip-flop"; var pattern:RegExp = /(\w+)-(\w+)/g; trace(str.replace(pattern, "$2-$1")); // flop-flip 也可以使用函数作为 replace() 方法的第二个参数。匹配的文本将被函数的返回值替换。 var str:String = "Now only $9.95!"; var price:RegExp = /\$([\d,]+.\d+)+/i; trace(str.replace(price, usdToEuro)); function usdToEuro(matchedSubstring:String, capturedMatch1:String, index:int, str:String):String { var usd:String = capturedMatch1; usd = usd.replace(",", ""); var exchangeRate:Number = 0.853690; var euro:Number = parseFloat(usd) * exchangeRate; const euroSymbol:String = String.fromCharCode(8364); return euro.toFixed(2) + " " + euroSymbol; } 在使用函数作为 replace() 方法的第二个形参时,将向该函数传递如下实参: • 字符串的匹配部分。 • 任何捕获的括号组匹配项。按这种方式传递的参数数目因括号匹配项的数目而异。您可以通过检查函数代码中的 arguments.length - 3 来确定括号匹配项的数目。 • 字符串中匹配开始的索引位置。 • 完整的字符串。 转换字符串的大小写 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如下例所示, toLowerCase() 方法和 toUpperCase() 方法分别将字符串中的英文字母字符转换为小写和大写: var str:String = "Dr. Bob Roberts, #9." trace(str.toLowerCase()); // dr. bob roberts, #9. trace(str.toUpperCase()); // DR. BOB ROBERTS, #9. 执行完这些方法后,源字符串仍保持不变。要转换源字符串,请使用下列代码: $ 代码 替换文本 $$ $ $& 匹配的子字符串。 $` 字符串中位于匹配的子字符串前面的部分。此代码使用左单直引号字符 (`) 而不是单直引号 (') 或左单弯引号 (' )。 $' 字符串中位于匹配的子字符串后的部分。此代码使用单直引号 (' )。 $n 第 n 个捕获的括号组匹配项,其中 n 是 1-9 之间的数字,而且 $n 后面没有十进制数字。 $nn 第 nn 个捕获的括号组匹配项,其中 nn 是一个十进制的两位数 (01-99)。如果未定义第 nn 个捕获内容,则替换文本为空字 符串。 17ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 str = str.toUpperCase(); 这些方法使用扩展字符,而并不仅限于 a–z 和 A–Z: var str:String = "José Barça"; trace(str.toUpperCase(), str.toLowerCase()); // JOSÉ BARÇA josé barça 字符串示例:ASCII 图表 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 此 ASCII 字符图示例说明了可以在 ActionScript 3.0 中使用 String 类实现的大量功能,其中包括: • 使用 String 类的 split() 方法可从由某个字符分隔的字符串中提取值 (制表符分隔的文本文件中的图像信息)。 • 使用多种字符串操作技术 (包括 split()、连接,以及使用 substring() 和 substr() 提取字符串的一部分)可将图像标题中每个 单词的第一个字母变为大写形式。 • 使用 getCharAt() 方法可从字符串中获取单个字符 (以确定对应于某个灰度位图值的 ASCII 字符)。 • 使用字符串连接可以按一次一个字符的方式建立图像的 ASCII 字符图表示形式。 ASCII 字符图 这一术语指的是图像的文本表示形式,即使用等宽字体字符 (如 Courier New 字符)的网格来绘制图像。下图 便是该应用程序所生成 ASCII 字符图的一个例子: 图形的 ASCII 字符图版本显示在右侧。 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在文件夹 Samples/AsciiArt 下找到 ASCIIArt 应用程序文件。该应用程序包含以下文件: 文件 说明 AsciiArtApp.mxml 或 AsciiArtApp.fla Flash (FLA) 或 Flex (MXML) 中的主应用程序文件 com/example/programmingas3/asciiArt/AsciiArtBuilder.as 此类提供了应用程序主要功能,包括了从文本文件中提取图像元数 据、加载图像和管理图像到文本的转换过程等功能。 com/example/programmingas3/asciiArt/BitmapToAsciiConverter.as 此类提供了用于将图像数据转换为字符串版本的 parseBitmapData() 方法。 com/example/programmingas3/asciiArt/Image.as 此类表示所加载的位图图像。18ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 提取由制表符分隔的值 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 此示例使用了将应用程序数据与应用程序本身分开存储的通行做法;通过这种方式,在数据发生更改时 (例如,添加了另一幅 图像或更改了图像标题),无需重新创建该 SWF 文件。在本例中,图像元数据 (包括图像标题、实际图像文件的 URL 以及用 来操作图像的某些值)存储在一个文本文件中 (项目中的 txt/ImageData.txt 文件)。该文本文件的内容如下所示: FILENAMETITLEWHITE_THRESHHOLDBLACK_THRESHHOLD FruitBasket.jpgPear, apple, orange, and bananad810 Banana.jpgA picture of a bananaC820 Orange.jpgorangeFF20 Apple.jpgpicture of an apple6E10 文件使用特定的制表符分隔格式。第一行为标题行。其余行包含要加载的每个位图的如下数据: • 位图的文件名。 • 位图的显示名称。 • 位图的白色阀值和黑色阀值。这些值是十六进制值,高于这些值或低于这些值的像素将分别被认为是全白或全黑的。 应用程序启动后, AsciiArtBuilder 类将加载并分析文本文件的内容,以便创建它要显示的图像的 “ 堆栈 ”,执行这些操作时 使用 AsciiArtBuilder 类的 parseImageInfo() 方法中的如下代码: var lines:Array = _imageInfoLoader.data.split("\n"); var numLines:uint = lines.length; for (var i:uint = 1; i < numLines; i++) { var imageInfoRaw:String = lines[i]; ... if (imageInfoRaw.length > 0) { // Create a new image info record and add it to the array of image info. var imageInfo:ImageInfo = new ImageInfo(); // Split the current line into values (separated by tab (\t) // characters) and extract the individual properties: var imageProperties:Array = imageInfoRaw.split("\t"); imageInfo.fileName = imageProperties[0]; imageInfo.title = normalizeTitle(imageProperties[1]); imageInfo.whiteThreshold = parseInt(imageProperties[2], 16); imageInfo.blackThreshold = parseInt(imageProperties[3], 16); result.push(imageInfo); } } 文本文件的完整内容包含在单个 String 实例中,即 _imageInfoLoader.data 属性。使用 split() 方法并以换行符 (\n) 为参数,将 该 String 实例分割到一个 Array (lines) 中,数组元素为文本文件的各个行。然后,代码使用循环来使用各行 (第一行除外, 因为它只包含标题而不包含实际内容)。在循环内部,再次使用 split() 方法将每行的内容分为一组值(名为 imageProperties 的 Array 对象)。在本例中,用于 split() 方法的参数为制表符 (\t),因为每行中的值均由制表符进行分隔。 com/example/programmingas3/asciiArt/ImageInfo.as 此类表示 ASCII 字符图像的元数据 (如标题、图像文件 URL 等)。 image/ 此文件夹包含应用程序使用的图像。 txt/ImageData.txt 此制表符分隔的文本文件中包含与应用程序要加载的图像有关的信 息。 文件 说明19ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 使用 String 的方法标准化图像标题 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 此应用程序的设计目标之一便是使用一种标准格式显示所有图像标题,即标题中每一个单词的第一个字母均为大写形式 (在英 文标题中通常不大写的少数单词除外)。应用程序并不假定文本文件已经包含格式正确的标题,它在从文本文件中提取标题时 对标题格式进行设置。 在前面的代码清单中,使用了如下代码行来提取每个图像元数据值: imageInfo.title = normalizeTitle(imageProperties[1]); 在该代码中,来自文本文件的图像标题在存储到 ImageInfo 对象之前先传递给 normalizeTitle() 方法进行处理: private function normalizeTitle(title:String):String { var words:Array = title.split(" "); var len:uint = words.length; for (var i:uint; i < len; i++) { words[i] = capitalizeFirstLetter(words[i]); } return words.join(" "); } 此方法使用 split() 方法将标题分割为各个单独的单词(由空格字符加以分隔),然后将每个单词传递给 capitalizeFirstLetter() 方 法进行处理,接着使用 Array 类的 join() 方法将单词重新合并为一个字符串。 如同其名称所表达的含义, capitalizeFirstLetter() 方法实际执行将每个单词的第一个字母变为大写形式的工作: /** * Capitalizes the first letter of a single word, unless it's one of * a set of words that are normally not capitalized in English. */ private function capitalizeFirstLetter(word:String):String { switch (word) { case "and": case "the": case "in": case "an": case "or": case "at": case "of": case "a": // Don't do anything to these words. break; default: // For any other word, capitalize the first character. var firstLetter:String = word.substr(0, 1); firstLetter = firstLetter.toUpperCase(); var otherLetters:String = word.substring(1); word = firstLetter + otherLetters; } return word; }20ACTIONSCRIPT 3.0 开发人员指南 使用字符串 上次更新 2014/12/1 在英文中,如果标题中某个单词为以下单词之一,则不会 将其首字符变为大写形 式:“and”、“the”、“in”、“an”、“or”、“at”、“of” 或 “a”。(这是相关规则的简化版本。)为了实现此逻辑,代码首先使用 switch 语句来检查单词是否为不应将其首字符大写的单词之一。如果是,代码直接跳出 switch 语句。另一方面,如果单词应大 写,则在几个步骤中完成此操作,如下所示: 1 使用 substr(0, 1) 提取出单词的第一个字母,该命令从位于索引位置 0 的字符 (即字符串的第一个字母,由第一个参数 0 指 定)开始提取子字符串。该子字符串的长度为一个字符 (由第二个参数 1 指定)。 2 使用 toUpperCase() 方法将该字符变为大写形式。 3 使用 substring(1) 提取原始单词的其余字符,该命令提取从索引位置 1 (第二个字母)开始直至字符串结尾 (通过将 substring() 方法的第二个参数保留为空进行指定)的子字符串。 4 使用字符串连接 firstLetter + otherLetters 将刚才变为大写形式的第一个字母与其余字母合并在一起,创建出最终的单词。 生成 ASCII 字符图文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 BitmapToAsciiConverter 类提供了将位图图像转换为其 ASCII 文本表示形式的功能。此过程由 parseBitmapData() 方法执 行,下面展示了该方法的部分工作过程: var result:String = ""; // Loop through the rows of pixels top to bottom: for (var y:uint = 0; y < _data.height; y += verticalResolution) { // Within each row, loop through pixels left to right: for (var x:uint = 0; x < _data.width; x += horizontalResolution) { ... // Convert the gray value in the 0-255 range to a value // in the 0-64 range (since that's the number of "shades of // gray" in the set of available characters): index = Math.floor(grayVal / 4); result += palette.charAt(index); } result += "\n"; } return result; 此代码首先定义一个名为 result 的 String 实例,用于构建位图图像的 ASCII 字符图版本。然后,它遍历源位图图像的每个像 素。通过使用若干颜色处理技术 (为了简便起见,此处省略了对这些技术的介绍),它将每个像素的红色、绿色和蓝色值转换 为单个灰度值 (一个介于 0-255 之间的数字)。接着,代码将该值除以 4 (如下所示)以将其转换为介于 0-63 之间的一个值, 此值存储在变量 index 中。(之所以使用 0-63 的范围,是因为此应用程序使用的可用 ASCII 字符的 “ 调色板 ” 包含 64 个值。) 该字符调色板在 BitmapToAsciiConverter 类中定义为一个 String 实例: // The characters are in order from darkest to lightest, so that their // position (index) in the string corresponds to a relative color value // (0 = black). private static const palette:String = "@#$%&8BMW*mwqpdbkhaoQ0OZXYUJCLtfjzxnuvcr[]{}1()|/?Il!i><+_~-;,. "; 因为变量 index 定义调色板中的哪个 ASCII 字符对应于位图图像中的当前像素,所以可使用 charAt() 方法从 palette 字符串中检 索该字符。然后,使用连接赋值运算符 (+=) 将其追加到 result 字符串实例。此外,在每行像素的末尾,会将一个换行符连接到 result 字符串的末尾,强制该行换行以创建新的一行字符 “ 像素 ”。 21 上次更新 2014/12/1 第 3 章 : 使用数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用数组可以在单数据结构中存储多个值。可以使用简单的索引数组 (使用固定有序整数索引存储值),也可以使用复杂的关 联数组 (使用任意键存储值)。数组也可以是多维的,即包含本身是数组的元素。最后,您可以对其元素均是同一数据类型的 实例的数组使用 Vector。 更多帮助主题 Array Vector 数组基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 编程时经常需要使用一组项目而不是单个对象。例如在一个音乐播放器应用程序中,您可能需要创建一个待播放歌曲列表。您 不希望必须为该列表中的每首歌曲都单独创建一个变量。更好的做法是将所有 Song 对象放在一个包中,从而能够将其作为一 个组进行使用。 数组是一种编程元素,它用作一组项目的容器,如一组歌曲。通常,数组中的所有项目都是相同类的实例,但这在 ActionScript 中并不是必需的。数组中的各个项目称为数组的 “ 元素 ”。可以将数组视为变量的 “ 文件柜 ”。变量可以作为元 素添加到数组中,就像将文件夹放到文件柜中一样。您可以将数组作为单个变量使用 (就像将整个文件柜搬到另一个地方一 样)。您可以将变量作为一个组使用(就像逐一浏览文件夹以搜索一条信息一样)。也可以分别访问这些变量(就像打开文件 柜并选择一个文件夹一样)。 例如,假设您要创建一个音乐播放器应用程序,用户可以在其中选择多首歌曲,并将这些歌曲添加到播放列表中。在您的 ActionScript 代码中有一个名为 addSongsToPlaylist() 的方法,该方法接受单个数组作为参数。无论要将多少首歌曲 (几首、 很多首甚至只有一首)添加到列表中,您都只调用一次 addSongsToPlaylist() 方法,并向其传递包含 Song 对象的数组。在 addSongsToPlaylist() 方法中,可以使用循环来逐个访问数组元素 (歌曲),并将歌曲实际添加到播放列表中。 最常见的 ActionScript 数组类型为 “ 索引数组 ”。在索引数组中,每个项目都存储在编号位置 (称为 “ 索引 ”)。可以使用该 编号来访问项目,如同地址一样。索引数组可以很好地满足大多数编程需要。 Array 类是用于表示索引数组的常见类。 索引数组常常用于存储具有相同类型的多个项目 (作为同一类的实例的对象)。 Array 类没有任何办法限制它所包含的项目的 类型。Vector 类是一种索引数组类型,其中单个数组中的所有项目都具有同一类型。使用 Vector 实例而不是 Array 实例还可 以提供性能改进和其他优势。从 Flash Player 10 和 Adobe AIR 1.5 开始提供 Vector 类。 索引数组的一个特殊用法是 “ 多维数组 ”。多维数组是一种索引数组,其中的元素也是索引数组 (这些数组又包含其他元素)。 另一种数组类型是 “ 关联数组 ”,该数组使用字符串 “ 键 ” (而不是数字索引)来标识各个元素。最后, ActionScript 3.0 还 包括表示 “ 字典 ” 的 Dictionary 类。字典是允许您将任何类型的对象用作键来区分元素的数组。 重要概念和术语 以下参考列表包含在对处理例程的数组和矢量进行编程时将遇到的重要术语: Array 用作容器以将多个对象组合在一起的对象。 数组访问 ([]) 运算符 一对中括号,其中含有唯一标识数组元素的索引或键。此语法用在数组变量名称之后,以指定数组的单个 元素而不是整个数组。22ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 关联数组 使用字符串键来标识各个元素的数组。 基本类型 允许 Vector 实例存储的对象的数据类型。 字典 其项目由一对对象 (称为键和值)组成的数组。它使用键来标识单个元素,而不是使用数字索引。 元素 数组中的单个项目。 索引 用于标识索引数组中的单个元素的数字 “ 地址 ”。 索引数组 标准类型的数组,将每个元素存储在编号位置中,并使用数字 (索引)来标识各个元素。 键 用于标识关联数组或字典中的单个元素的字符串或对象。 多维数组 包含的项目是数组 (而不是单个值)的数组。 T 本文档中使用的标准约定,用于表示 Vector 实例的基本类型(与具体的基本类型无关)。T 约定用于表示类名称,如 Type 参数说明中所示。(“T” 表示 “ 类型 ”,如同在 “ 数据类型 ” 中一样。)。 类型参数 与 Vector 类名称一起使用以指定 Vector 的基本类型 (它存储的对象的数据类型)的语法。该语法包括一个点 (.), 然后是由尖括号 (<>) 括起来的数据类型名称。放在一起后类似于:Vector.。在本文档中,在类型参数中指定的类通常表示 为 T。 Vector 一种数组类型,其所有元素都是同一数据类型的实例。 索引数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 索引数组存储一系列经过组织的单个或多个值,其中的每个值都可以通过使用一个无符号整数值进行访问。第一个索引始终是 数字 0,且添加到数组中的每个后续元素的索引以 1 为增量递增。在 ActionScript 3.0 中,有两个类可用作索引数组:Array 类和 Vector 类。 索引数组使用无符号 32 位整数作为索引号。索引数组的最大大小为 232 - 1,即 4,294,967,295。如果尝试创建超过该最大大小 的数组,则会导致运行时错误。 若要访问索引数组中的单个元素,请使用数组访问 ([]) 运算符指定要访问的元素的索引位置。例如,下面的代码表示名为 songTitles 的索引数组中的第一个元素 (位于索引 0 处的元素): songTitles[0] 数组变量名称后跟索引 (在中括号中)的组合用作一个标识符。(换句话说,可以按照变量名称的任何使用方式来使用这个组 合)。可以在赋值语句左侧使用名称和索引来向索引数组元素赋值。 songTitles[1] = "Symphony No. 5 in D minor"; 同样,可以在赋值语句右侧使用名称和索引来检索索引数组元素的值。 var nextSong:String = songTitles[2]; 您还可以在中括号中使用变量而不是提供显式值。(变量必须包含一个非负整数值,如 uint、正 int 或正整数 Number 实 例)。此方法通常用于 “ 循环访问 ” 索引数组中的元素,并对某些元素或所有元素执行操作。下面的代码清单演示了这种方法。 这段代码使用循环来访问名为 oddNumbers 的 Array 对象中的每个值。它使用 trace() 语句以 “oddNumber[index] = value” 的形式输出每个值: var oddNumbers:Array = [1, 3, 5, 7, 9, 11]; var len:uint = oddNumbers.length; for (var i:uint = 0; i < len; i++) { trace("oddNumbers[" + i.toString() + "] = " + oddNumbers[i].toString()); }23ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 Array 类 索引数组的第一个类型为 Array 类。Array 实例的值可以为任意数据类型。同一 Array 对象中包含的对象可以具有不同的数据 类型。例如,一个 Array 实例可以在索引 0 处有 String 值,在索引 1 处有 Number 实例,而在索引 2 处有 XML 对象。 Vector 类 ActionScript 3.0 中可用的另一种索引数组类型为 Vector 类。 Vector 实例是 “ 指定类型的数组 ”,这表示 Vector 实例中的 所有元素始终具有同一数据类型。 注: 从 Flash Player 10 和 Adobe AIR 1.5 开始提供 Vector 类。 在声明 Vector 变量或实例化 Vector 对象时,要明确指定 Vector 可以包含的对象的数据类型。指定的数据类型称为 Vector 的 “ 基本类型 ”。在运行时和编译时 (在严格模式下),会检查任何设置 Vector 元素的值或从 Vector 检索值的代码。如果要 添加或检索的对象的数据类型与 Vector 的基本类型不匹配,则会发生错误。 除数据类型限制之外, Vector 类还具有一些其他限制,从而有别于 Array 类: • Vector 是一种密集数组。即使某个 Array 对象在位置 1 到 6 没有值,该对象的索引 0 和 7 处也可以有值。但是, Vector 的每个索引位置都必须有值 (或为 null)。 • Vector 还可以是固定长度。这表示 Vector 包含的元素数不能更改。 • 对 Vector 的元素的访问需要接受范围检查。绝对不能从大于最后一个元素索引 (length - 1) 的索引中读取值。绝对不能对 超过当前最后一个索引一个以上位置的索引设置值 (也就是说,只能在现有索引或索引 [length] 处设置值)。 由于 Vector 具有这些限制,因此 Vector 相对于所有元素均为单个类的实例的 Array 实例有三个主要优点: • 性能:使用 Vector 实例时的数组元素访问和迭代的速度比使用 Array 实例时的速度要快很多。 • 类型安全性:在严格模式下,编译器可以识别数据类型错误。这类错误的例子包括将数据类型错误的值分配给 Vector 或从 Vector 中读取值时使用错误的数据类型。在运行时,当向 Vector 对象添加数据或从 Vector 对象读取数据时也会检查数据 类型。但请注意,当使用 push() 方法或 unshift() 方法向 Vector 添加值时,在编译时不会检查参数的数据类型。不过在使用 这些方法时,仍会在运行时检查值。 • 可靠性:与 Array 相比,运行时范围检查 (或固定长度检查)大大提高了可靠性。 除了有一些限制和优点以外, Vector 类与 Array 类非常相似。 Vector 对象的属性和方法与 Array 的属性和方法类似 (大多 数情况下完全相同)。对于大多数需要使用所有元素都具有相同数据类型的 Array 的情况, Vector 实例更为可取。 创建数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用多种方法来创建 Array 实例或 Vector 实例。但是,创建每种数组类型的方法多少有些不同。 创建 Array 实例 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以通过调用 Array() 构造函数或使用 Array 文本语法来创建 Array 对象。 Array() 构造函数有三种使用方式。第一种,如果调用不带参数的构造函数,会得到空数组。可以使用 Array 类的 length 属性 来验证数组是否不包含元素。例如,下面的代码调用不带参数的 Array() 构造函数: var names:Array = new Array(); trace(names.length); // output: 0 第二种,如果将一个数字用作 Array() 构造函数的唯一参数,则会创建长度等于此数值的数组,并且每个元素的值都设置为 undefined。参数必须为介于值 0 和 4,294,967,295 之间的无符号整数。例如,下面的代码调用带有一个数字参数的 Array() 构 造函数:24ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 var names:Array = new Array(3); trace(names.length); // output: 3 trace(names[0]); // output: undefined trace(names[1]); // output: undefined trace(names[2]); // output: undefined 第三种,如果调用构造函数并传递一个元素列表作为参数,将创建具有与每个参数对应的元素的数组。下面的代码将三个参数 传递给 Array() 构造函数: var names:Array = new Array("John", "Jane", "David"); trace(names.length); // output: 3 trace(names[0]); // output: John trace(names[1]); // output: Jane trace(names[2]); // output: David 也可以使用 Array 文本创建数组。可以将 Array 文本直接分配给数组变量,如下面的示例所示: var names:Array = ["John", "Jane", "David"]; 创建 Vector 实例 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 可以通过调用 Vector.() 构造函数创建 Vector 实例。还可以通过调用 Vector.() 全局函数创建 Vector。该函数将指定对 象转换为 Vector 实例。在 Flash Professional CS5 和更高版本、Flash Builder 4 和更高版本以及 Flex 4 和更高版本中,还可 以使用 Vector 文本语法创建 Vector 实例。 只要声明 Vector 变量 (Vector 方法参数或方法返回类型也一样),就需要指定 Vector 变量的基本类型。在通过调用 Vector.() 构造函数创建 Vector 实例。换句话说,只要在 ActionScript 中使用术语 Vector,就需要指定基本类型。 可以使用 type 参数语法指定 Vector 的基本类型。在代码中,类型参数紧跟单词 Vector。它包括一个点 (.),然后是由尖括号 (<>) 括起来的基类名称,如此示例中所示: var v:Vector.; v = new Vector.(); 在此示例的第一行内容中,变量 v 声明为 Vector. 实例。换句话说,它表示只能包含 String 实例的索引数组。第二行 调用 Vector() 构造函数创建一个具有相同 Vector 类型的实例(也就是其中所有元素都是 String 对象的 Vector)。该示例将该 对象分配给 v。 使用 Vector.() 构造函数 如果使用不带任何参数的 Vector.() 构造函数,则该函数会创建一个空的 Vector 实例。可以通过检查 Vector 的 length 属 性来测试它是否为空。例如,下面的代码调用不带任何参数的 Vector.() 构造函数: var names:Vector. = new Vector.(); trace(names.length); // output: 0 如果您预先知道 Vector 最初需要多少元素,则可以预定义 Vector 中的元素数。若要使用特定数量的元素创建 Vector,请将 元素数作为第一个参数 (length 参数)进行传递。因为 Vector 元素不能为空,所以会使用具有基本类型的实例填充这些元 素。如果基本类型是允许使用 null 值的引用类型,则所有元素都包含 null。否则,所有元素都包含该类的默认值。例如, uint 变量不能为 null。因此,在下面的代码清单中,使用七个元素创建名为 ages 的 Vector,其中每个元素都包含值 0: var ages:Vector. = new Vector.(7); trace(ages); // output: 0,0,0,0,0,0,0 最后,还可以使用 Vector.() 构造函数创建固定长度 Vector,方法是将 true 作为第二个参数 (fixed 参数)进行传递。在这 种情况下,将使用指定的元素数创建 Vector,且元素数不可更改。但是请注意,仍然可以更改固定长度 Vector 的元素值。25ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 使用 Vector 文本语法构造函数 在 Flash Professional CS5 和更高版本、Flash Builder 4 和更高版本以及 Flex 4 和更高版本中,可以向 Vector.() 构造函 数传递值列表来指定 Vector 的初始值: // var v:Vector. = new [E0, ..., En-1 ,]; // For example: var v:Vector. = new [0,1,2,]; 下列信息适用于此语法: • 尾部的逗号是可选的。 • 数组中不支持空项目;类似 var v:Vector. = new [0,,2,] 的语句会引发编译器错误。 • 无法为 Vector 实例指定默认长度。该长度与初始化列表中的元素数相同。 • 无法指定 Vector 实例是否具有固定长度。应使用 fixed 属性。 • 如果作为值传递的项目与指定类型相匹配,则可能会发生数据丢失或出现错误。例如: var v:Vector. = new [4.2]; // compiler error when running in strict mode trace(v[0]); //returns 4 when not running in strict mode 使用 Vector.() 全局函数 除了 Vector.() 和 Vector 文本语法构造函数之外,还可以使用 Vector.() 全局函数创建 Vector 对象。Vector.() 全局 函数是一个转换函数。当调用 Vector.() 全局函数时,需指定该方法返回的 Vector 的基本类型。可将单个索引数组 (Array 或 Vector 实例)作为参数进行传递。该方法随后返回具有指定基本类型的 Vector,其中包含源数组参数中的值。下 面的代码清单演示了用于调用 Vector.() 全局函数的语法: var friends:Vector. = Vector.(["Bob", "Larry", "Sarah"]); Vector.() 全局函数在两个级别上执行数据类型转换。首先,当 Array 实例传递给该函数时,会返回 Vector 实例。其次, 无论源数组是 Array 还是 Vector 实例,该函数都会试图将源数组的元素转换为基本类型的值。该转换使用标准 ActionScript 数据类型转换规则。例如,下面的代码清单将源 Array 中的 String 值转换为结果 Vector 中的整数。第一个值 (“1.5”)的小 数部分被截断,非数字的第三个值 (“Waffles”)在结果中转换为 0: var numbers:Vector. = Vector.(["1.5", "17", "Waffles"]); trace(numbers); // output: 1,17,0 如果无法转换任何源元素,则会发生错误。 当代码调用 Vector.() 全局函数时,如果源数组中的某个元素是指定基本类型的子类的实例,则该元素会添加到结果 Vector 中 (不发生错误)。只有使用 Vector.() 全局函数才能将基本类型为 T 的 Vector 转换为基本类型为 T 的超类的 Vector。 插入数组元素 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 用于将元素添加到索引数组的最基本方法是使用数组访问 ([]) 运算符。若要设置索引数组元素的值,请在赋值语句的左侧使用 Array 或 Vector 对象名称和索引编号: songTitles[5] = "Happy Birthday"; 如果 Array 或 Vector 在该索引处还没有元素,则会创建该索引并将值存储在那里。如果该索引处存在值,则新值会替换现有 值。 Array 对象允许您在任何索引位置创建元素。但是对于 Vector 对象,您只能向现有索引或下一个可用索引赋值。下一个可用 索引对应于 Vector 对象的 length 属性。向 Vector 对象添加新元素的最安全方式是使用类似于下面的清单的代码: myVector[myVector.length] = valueToAdd;26ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 可以使用 Array 和 Vector 类的三种方法(push()、unshift() 和 splice())将元素插入索引数组。push() 方法用于在数组末尾添 加一个或多个元素。换言之,使用 push() 方法在数组中插入的最后一个元素将具有最大索引号。 unshift() 方法用于在数组开头 插入一个或多个元素,并且始终在索引号 0 处插入。 splice() 方法用于在数组中的指定索引处插入任意数目的项目。 下面的示例对所有三种方法进行了说明。它创建一个名为 planets 的数组,以便按照行星距离太阳由近到远的顺序存储各个行星 的名称。首先,调用 push() 方法以添加初始项目 Mars。接着,调用 unshift() 方法在数组开头插入项 Mercury。最后,调用 splice() 方法在 Mercury 之后和 Mars 之前插入项 Venus 和 Earth。传递给 splice() 的第一个参数是整数 1,它用于指示从索引 1 处开始插入。传递给 splice() 的第二个参数是整数 0,它指示不应删除任何项。传递给 splice() 的第三和第四个参数 Venus 和 Earth 为要插入的项。 var planets:Array = new Array(); planets.push("Mars"); // array contents: Mars planets.unshift("Mercury"); // array contents: Mercury,Mars planets.splice(1, 0, "Venus", "Earth"); trace(planets); // array contents: Mercury,Venus,Earth,Mars push() 和 unshift() 方法均返回一个无符号整数,它们表示修改后的数组长度。在用于插入元素时,splice() 方法返回空数组,这 看上去也许有点奇怪,但考虑到 splice() 方法的多用途性,您便会觉得这样更有意义。通过使用 splice() 方法,不仅可以将元素 插入到数组中,而且还可以从数组中删除元素。用于删除元素时, splice() 方法将返回包含被删除元素的数组。 注: 如果某个 Vector 对象的 fixed 属性为 true,则不能更改该 Vector 中的元素数。如果尝试使用此处介绍的方法向固定长度 Vector 添加新元素,则会发生错误。 检索值和删除数组元素 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 用于检索索引数组中的元素值的最简单方法是使用数组访问 ([]) 运算符。若要检索索引数组元素的值,请在赋值语句的右侧使 用 Array 或 Vector 对象名称和索引编号: var myFavoriteSong:String = songTitles[3]; 可以尝试使用不存在元素的位置的索引来检索 Array 或 Vector 中的值。在这种情况下, Array 对象返回未定义的值,而 Vector 会引发 RangeError 异常。 可以使用 Array 和 Vector 类的三种方法(pop()、shift() 和 splice())删除元素。pop() 方法用于从数组末尾删除一个元素。换 言之,它将删除位于最大索引号处的元素。 shift() 方法用于从数组开头删除一个元素,也就是说,它始终删除索引号 0 处的元 素。 splice() 方法既可用来插入元素,也可以删除任意数目的元素,其操作的起始位置位于由发送到此方法的第一个参数指定的 索引号处。 下面的示例使用所有三种方法从 Array 实例中删除元素。该示例创建一个名为 oceans 的 Array,用于存储较大水域的名称。 Array 中的某些名称为湖泊的名称而非海洋的名称,因此需要将其删除。 首先,使用 splice() 方法删除项 Aral 和 Superior,并插入项 Atlantic 和 Indian。传递给 splice() 的第一个参数是整数 2,它指示 应从列表中的第三个项 (即索引 2 处)开始执行操作。第二个参数 2 指示应删除两个项。其余两个参数 Atlantic 和 Indian 是要 在索引 2 处插入的值。 然后,使用 pop() 方法删除数组中的最后一个元素 Huron。最后,使用 shift() 方法删除数组中的第一个项 Victoria。 var oceans:Array = ["Victoria", "Pacific", "Aral", "Superior", "Indian", "Huron"]; oceans.splice(2, 2, "Arctic", "Atlantic"); // replaces Aral and Superior oceans.pop(); // removes Huron oceans.shift(); // removes Victoria trace(oceans);// output: Pacific,Arctic,Atlantic,Indian pop() 和 shift() 方法均返回已删除的项。对于 Array 实例,由于数组可以包含任意数据类型的值,因而返回值的数据类型为 Object。对于 Vector 实例,返回值的数据类型是 Vector 的基本类型。splice() 方法返回包含所删除的值的 Array 或 Vector。 可以更改 oceans Array 示例,以使 splice() 调用将返回的 Array 分配给新的 Array 变量,如下面的示例所示:27ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 var lakes:Array = oceans.splice(2, 2, "Arctic", "Atlantic"); trace(lakes); // output: Aral,Superior 您可能会遇到对 Array 对象元素使用 delete 运算符的代码。 delete 运算符会将 Array 元素的值设置为 undefined,但它不会从 Array 中删除元素。例如,下面的代码对 oceans Array 中的第三个元素使用 delete 运算符,但此 Array 的长度仍然为 5: var oceans:Array = ["Arctic", "Pacific", "Victoria", "Indian", "Atlantic"]; delete oceans[2]; trace(oceans);// output: Arctic,Pacific,,Indian,Atlantic trace(oceans[2]); // output: undefined trace(oceans.length); // output: 5 可以使用数组的 length 属性截断 Array 或 Vector。如果您将某个索引数组的 length 属性设置为小于该数组的当前长度的长 度,则该数组会被截断,从而删除存储在比 length 的新值减 1 大的索引编号处的所有元素。例如,如果 oceans 数组进行了排 序,以使所有有效项都位于数组开头,则可以使用 length 属性删除位于数组后部的项,如下面的代码所示: var oceans:Array = ["Arctic", "Pacific", "Victoria", "Aral", "Superior"]; oceans.length = 2; trace(oceans); // output: Arctic,Pacific 注: 如果某个 Vector 对象的 fixed 属性为 true,则不能更改该 Vector 中的元素数。如果尝试使用此处介绍的方法删除固定长 度 Vector 中的元素或截断固定长度 Vector,则会发生错误。 对数组排序 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用三种方法 (reverse()、sort() 和 sortOn())通过排序或反向排序来更改索引数组的顺序。所有这些方法都用来修改现有 数组。下表概述了这些方法及其针对 Array 和 Vector 对象的行为: reverse() 方法 reverse() 方法不带参数,也不返回值,但可以将数组从当前顺序切换为相反顺序。以下示例颠倒了 oceans 数组中列出的海洋顺 序: var oceans:Array = ["Arctic", "Atlantic", "Indian", "Pacific"]; oceans.reverse(); trace(oceans); // output: Pacific,Indian,Atlantic,Arctic 使用 sort() 方法的基本排序 (仅适用于 Array 类) 对于 Array 实例, sort() 方法按照 “ 默认排序顺序 ” 重新排列数组中的元素。默认排序顺序具有以下特征: • 排序区分大小写,也就是说大写字符优先于小写字符。例如,字母 D 优先于字母 b。 • 排序按照升序进行,也就是说低位字符代码 (例如 A)优先于高位字符代码 (例如 B)。 • 排序将相同的值互邻放置,并且不区分顺序。 • 排序基于字符串,也就是说,在比较元素之前,先将其转换为字符串 (例如,10 优先于 3,因为相对于字符串 "3" 而言,字 符串 "1" 具有低位字符代码)。 方法 Array 行为 Vector 行为 reverse() 更改元素的顺序,使最后一个元素变为第一个元素,倒数第二个元素变为第二 个元素,依此类推。 与 Array 行为相同 sort() 用于按照各种预定义的方式对 Array 的元素进行排序 (如字母顺序或数字顺 序)。还可以指定自定义排序算法。 根据您指定的自定义排序算法对元素进行排序 sortOn() 用于对具有一个或多个公共属性的对象进行排序,排序时指定这样的属性作为 排序键 在 Vector 类中不可用28ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 您也许需要不区分大小写或者按照降序对 Array 进行排序,或者您的数组中包含数字,从而需要按照数字顺序而非字母顺序进 行排序。Array 类的 sort() 方法具有 options 参数,可通过该参数改变默认排序顺序的各个特征。options 是由 Array 类中的一 组静态常量定义的,如以下列表所示: • Array.CASEINSENSITIVE:此选项可使排序不区分大小写。例如,小写字母 b 优先于大写字母 D。 • Array.DESCENDING:用于颠倒默认的升序排序。例如,字母 B 优先于字母 A。 • Array.UNIQUESORT:如果发现两个相同的值,此选项将导致排序中止。 • Array.NUMERIC:这会导致排序按照数字顺序进行,比方说 3 优先于 10。 以下示例重点说明了这些选项中的某些选项。它创建一个名为 poets 的 Array,并使用几种不同的选项对其进行排序。 var poets:Array = ["Blake", "cummings", "Angelou", "Dante"]; poets.sort(); // default sort trace(poets); // output: Angelou,Blake,Dante,cummings poets.sort(Array.CASEINSENSITIVE); trace(poets); // output: Angelou,Blake,cummings,Dante poets.sort(Array.DESCENDING); trace(poets); // output: cummings,Dante,Blake,Angelou poets.sort(Array.DESCENDING | Array.CASEINSENSITIVE); // use two options trace(poets); // output: Dante,cummings,Blake,Angelou 使用 sort() 方法的自定义排序 (适用于 Array 和 Vector 类) 除了可用于 Array 对象的基本排序之外,您还可以定义自定义排序规则。此方法是可用于 Vector 类的唯一一种形式的 sort() 方法。若要定义自定义排序,请编写自定义排序函数,并将该函数作为参数传递给 sort() 方法。 例如,如果有一个名称列表,其中每个列表元素都包含一个人的全名,但现在要按照姓氏对列表排序,则必须使用自定义排序 函数分析每个元素,并在排序函数中使用姓氏。下面的代码说明如何使用作为参数传递给 Array.sort() 方法的自定义函数来完成 上述工作: var names:Array = new Array("John Q. Smith", "Jane Doe", "Mike Jones"); function orderLastName(a, b):int { var lastName:RegExp = /\b\S+$/; var name1 = a.match(lastName); var name2 = b.match(lastName); if (name1 < name2) { return -1; } else if (name1 > name2) { return 1; } else { return 0; } } trace(names); // output: John Q. Smith,Jane Doe,Mike Jones names.sort(orderLastName); trace(names); // output: Jane Doe,Mike Jones,John Q. Smith 自定义排序函数 orderLastName() 使用正则表达式从每个元素中提取姓,以用于比较操作。针对 names 数组调用 sort() 方法时, 函数标识符 orderLastName 用作唯一的参数。排序函数接受两个参数 a 和 b,因为它每次对两个数组元素进行操作。排序函数 的返回值指示应如何对元素排序: • 返回值 -1 指示第一个参数 a 优先于第二个参数 b。 29ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 • 返回值 1 指示第二个参数 b 优先于第一个参数 a。 • 返回值为 0 指示元素具有相同的排序优先级。 sortOn() 方法 (仅适用于 Array 类) sortOn() 方法是为具有包含对象的元素的 Array 对象设计的。这些对象应至少具有一个可用作排序键的公共属性。如果将 sortOn() 方法用于任何其他类型的数组,则会产生意外结果。 注: Vector 类不包含 sortOn() 方法。此方法仅用于 Array 对象。 下面的示例修改 poets Array,以使每个元素均为对象而非字符串。每个对象既包含诗人的姓氏又包含诗人的出生年份。 var poets:Array = new Array(); poets.push({name:"Angelou", born:"1928"}); poets.push({name:"Blake", born:"1757"}); poets.push({name:"cummings", born:"1894"}); poets.push({name:"Dante", born:"1265"}); poets.push({name:"Wang", born:"701"}); 可以使用 sortOn() 方法,按照 born 属性对 Array 进行排序。 sortOn() 方法定义两个参数 fieldName 和 options。必须将 fieldName 参数指定为字符串。在以下示例中,使用两个参数 "born" 和 Array.NUMERIC 来调用 sortOn()。Array.NUMERIC 参 数用于确保按照数字顺序进行排序,而不是按照字母顺序。即使所有数字具有相同的数位,这也是一种很好的做法,因为当后 来在数组中添加较少数位或较多数位的数字时,它会确保排序如期继续进行。 poets.sortOn("born", Array.NUMERIC); for (var i:int = 0; i < poets.length; ++i) { trace(poets[i].name, poets[i].born); } /* output: Wang 701 Dante 1265 Blake 1757 cummings 1894 Angelou 1928 */ 在不修改原始数组的情况下进行排序 (仅适用于 Array 类) 通常, sort() 和 sortOn() 方法用于修改 Array。如果要对 Array 排序而又不修改现有数组,请将 Array.RETURNINDEXEDARRAY 常量作为 options 参数的一部分进行传递。此选项将指示方法返回反映排序的新 Array,同 时保留原始 Array 原封不动。方法返回的 Array 为由反映新排序顺序的索引号组成的简单 Array,不包含原始 Array 的任何元 素。例如,若要根据出生年份对 poets Array 排序而不修改该 Array,请在为 options 形参传递的实参中包括 Array.RETURNINDEXEDARRAY 常量。 下面的示例将返回的索引信息存储在名为 indices 的 Array 中,然后使用 indices 数组和未修改的 poets 数组按出生年份的顺序 输出诗人:30ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 var indices:Array; indices = poets.sortOn("born", Array.NUMERIC | Array.RETURNINDEXEDARRAY); for (var i:int = 0; i < indices.length; ++i) { var index:int = indices[i]; trace(poets[index].name, poets[index].born); } /* output: Wang 701 Dante 1265 Blake 1757 cummings 1894 Angelou 1928 */ 查询数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Array 和 Vector 类的四种方法 concat()、 join()、 slice() 和 toString() 均可用于查询数组的信息,而不修改数组。 concat() 和 slice() 方法返回新数组;而 join() 和 toString() 方法返回字符串。 concat() 方法将新数组和元素列表作为参数,并将其与现有数 组结合起来创建新数组。 slice() 方法有两个名为 startIndex 和 endIndex 的参数,并返回一个新数组,新数组中包含从现有数组 “ 分离 ” 的元素副本。分离从 startIndex 处的元素开始,到 endIndex 处的前一个元素结束。值得强调的是, endIndex 处的元素 不包括在返回值中。 以下示例通过 concat() 和 slice() 方法,使用其他数组的元素创建新数组: var array1:Array = ["alpha", "beta"]; var array2:Array = array1.concat("gamma", "delta"); trace(array2); // output: alpha,beta,gamma,delta var array3:Array = array1.concat(array2); trace(array3); // output: alpha,beta,alpha,beta,gamma,delta var array4:Array = array3.slice(2,5); trace(array4); // output: alpha,beta,gamma 可以使用 join() 和 toString() 方法查询数组,并将其内容作为字符串返回。如果 join() 方法没有使用参数,则这两个方法的行为 相同,它们都返回一个字符串,其中包含数组中所有元素的逗号分隔列表。与 toString() 方法不同, join() 方法接受名为 delimiter 的参数;可以使用此参数,选择要用作返回字符串中各个元素之间分隔符的符号。 下面的示例创建名为 rivers 的 Array,并调用 join() 和 toString() 以便采用字符串形式返回该 Array 中的值。 toString() 方法用 于返回以逗号分隔的值 (riverCSV) ;而 join() 方法用于返回以 + 字符分隔的值。 var rivers:Array = ["Nile", "Amazon", "Yangtze", "Mississippi"]; var riverCSV:String = rivers.toString(); trace(riverCSV); // output: Nile,Amazon,Yangtze,Mississippi var riverPSV:String = rivers.join("+"); trace(riverPSV); // output: Nile+Amazon+Yangtze+Mississippi 对于 join() 方法,应注意的一个问题是,无论为主数组元素指定的分隔符是什么,为嵌套 Array 或 Vector 实例返回的值始终 以逗号作为分隔符,如下面的示例所示: var nested:Array = ["b","c","d"]; var letters:Array = ["a",nested,"e"]; var joined:String = letters.join("+"); trace(joined); // output: a+b,c,d+e31ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 关联数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 关联数组有时也称为 “ 哈希 ” 或 “ 映射 ”,它使用 “ 键 ” 而非数字索引来组织存储的值。关联数组中的每个键都是用于访问一 个存储值的唯一字符串。关联数组为 Object 类的实例,也就是说每个键都与一个属性名称对应。关联数组是键和值对的无序 集合。在代码中,不应期望关联数组的键按特定的顺序排列。 ActionScript 3.0 中还引入了名为 “ 字典 ” 的高级关联数组类型。字典是 flash.utils 包中的 Dictionary 类的实例,使用的键 可以为任意数据类型。换言之,字典的键不局限于 String 类型的值。 具有字符串键的关联数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 3.0 中有两种创建关联数组的方式。第一种方式是使用 Object 实例。使用 Object 实例,您可以通过对象文本 来初始化数组。 Object 类的实例 (也称为 “ 通用对象 ”)在功能上等同于关联数组。通用对象的每个属性名称都用作键,提供 对存储的值的访问。 下面的示例创建一个名为 monitorInfo 的关联数组,并使用对象文本初始化具有两个键和值对的数组: var monitorInfo:Object = {type:"Flat Panel", resolution:"1600 x 1200"}; trace(monitorInfo["type"], monitorInfo["resolution"]); // output: Flat Panel 1600 x 1200 如果在声明数组时不需要初始化,可以使用 Object 构造函数创建数组,如下所示: var monitorInfo:Object = new Object(); 使用对象文本或 Object 类构造函数创建数组后,可以使用数组访问 ([]) 运算符或点运算符 (.)。以下示例将两个新值添加到 monitorArray 中: monitorInfo["aspect ratio"] = "16:10"; // bad form, do not use spaces monitorInfo.colors = "16.7 million"; trace(monitorInfo["aspect ratio"], monitorInfo.colors); // output: 16:10 16.7 million 请注意,名为 aspect ratio 的键包含空格字符。可以使用数组访问 ([]) 运算符,但是如果尝试使用点运算符,则会生成错误。不 建议在键名称中使用空格。 创建关联数组的第二种方式是使用 Array 构造函数(或任何动态类的构造函数),然后使用数组访问 ([]) 运算符或点运算符 (.) 将键和值对添加到数组中。如果将关联数组声明为数组类型,则将无法使用对象文本初始化该数组。以下示例使用 Array 构造 函数创建一个名为 monitorInfo 的关联数组,并添加一个名为 type 的键和一个名为 resolution 的键以及它们的值: var monitorInfo:Array = new Array(); monitorInfo["type"] = "Flat Panel"; monitorInfo["resolution"] = "1600 x 1200"; trace(monitorInfo["type"], monitorInfo["resolution"]); // output: Flat Panel 1600 x 1200 使用 Array 构造函数创建关联数组没有什么优势。即使使用 Array 构造函数或 Array 数据类型,也不能将 Array 类的 Array.length 属性或任何方法用于关联数组。最好将 Array 构造函数用于创建索引数组。32ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 具有对象键的关联数组 (字典) Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 Dictionary 类创建使用对象而非字符串作为键的关联数组。这样的数组有时候也称作字典、哈希或映射。例如,考 虑这样一个应用程序,它可根据 Sprite 对象与特定容器的关联确定 Sprite 对象的位置。可以使用 Dictionary 对象,将每个 Sprite 对象映射到一个容器。 以下代码创建三个用作 Dictionary 对象的键的 Sprite 对象实例。它为每个键分配了值 GroupA 或 GroupB。值可以是任意数据 类型,但在此示例中, GroupA 和 GroupB 均为 Object 类的实例。然后,可以使用数组访问 ([]) 运算符访问与每个键关联的 值,如下面的代码所示: import flash.display.Sprite; import flash.utils.Dictionary; var groupMap:Dictionary = new Dictionary(); // objects to use as keys var spr1:Sprite = new Sprite(); var spr2:Sprite = new Sprite(); var spr3:Sprite = new Sprite(); // objects to use as values var groupA:Object = new Object(); var groupB:Object = new Object(); // Create new key-value pairs in dictionary. groupMap[spr1] = groupA; groupMap[spr2] = groupB; groupMap[spr3] = groupB; if (groupMap[spr1] == groupA) { trace("spr1 is in groupA"); } if (groupMap[spr2] == groupB) { trace("spr2 is in groupB"); } if (groupMap[spr3] == groupB) { trace("spr3 is in groupB"); } 使用对象键循环访问 您可以使用 for..in 循环或 for each..in 循环来遍历 Dictionary 对象的内容。 for..in 循环用于基于键进行遍历;而 for each..in 循 环用于基于与每个键关联的值进行遍历。 使用 for..in 循环可以直接访问 Dictionary 对象的对象键。还可以使用数组访问 ([]) 运算符访问 Dictionary 对象的值。下面的 代码使用前面的 groupMap 字典示例来说明如何使用 for..in 循环来遍历 Dictionary 对象: for (var key:Object in groupMap) { trace(key, groupMap[key]); } /* output: [object Sprite] [object Object] [object Sprite] [object Object] [object Sprite] [object Object] */33ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 使用 for each..in 循环可以直接访问 Dictionary 对象的值。下面的代码也使用 groupMap 字典来说明如何使用 for each..in 循环 来遍历 Dictionary 对象: for each (var item:Object in groupMap) { trace(item); } /* output: [object Object] [object Object] [object Object] */ 对象键和内存管理 Adobe® Flash® Player 和 Adobe® AIR™ 使用垃圾回收系统来恢复不再使用的内存。当对象不具有指向它的引用时,即可对其 进行垃圾回收,并会在下次执行垃圾回收系统时恢复内存。例如,下面的代码创建一个新对象,并将对此对象的引用分配给变 量 myObject: var myObject:Object = new Object(); 只要有对此对象的引用,垃圾回收系统就不会恢复此对象占用的内存。如果更改 myObject 的值以使其指向其他对象或将其设 置为值 null,并且没有对原始对象的其他引用,则可以对原始对象占用的内存进行垃圾回收。 如果将 myObject 用作 Dictionary 对象中的键,则会创建对原始对象的另一个引用。例如,下面的代码创建两个对象引用 (myObject 变量和 myMap 对象中的键): import flash.utils.Dictionary; var myObject:Object = new Object(); var myMap:Dictionary = new Dictionary(); myMap[myObject] = "foo"; 若要使 myObject 引用的对象能够进行垃圾回收,您必须删除对它的所有引用。在此情况下,必须更改 myObject 的值并从 myMap 中删除 myObject 键,如以下代码所示: myObject = null; delete myMap[myObject]; 或者,可以使用 Dictionary 构造函数的 useWeakReference 参数,以使所有字典键均成为 “ 弱引用 ”。垃圾回收系统忽略弱引 用,也就是说只具有弱引用的对象可以进行垃圾回收。例如,在下面的代码中,您不需要从 myMap 中删除 myObject 键就可以 使该对象能够进行垃圾回收: import flash.utils.Dictionary; var myObject:Object = new Object(); var myMap:Dictionary = new Dictionary(true); myMap[myObject] = "foo"; myObject = null; // Make object eligible for garbage collection. 多维数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 多维数组将其他数组作为其元素。例如,考虑一个任务列表,它存储为有索引的字符串数组: var tasks:Array = ["wash dishes", "take out trash"];34ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 如果要将一周中每天的任务存储为一个单独的列表,可以创建一个多维数组,一周中的每天使用一个元素。每个元素包含一个 与 tasks 数组类似的索引数组,而该索引数组存储任务列表。在多维数组中,可以使用任意组合的索引数组和关联数组。以下部 分中的示例使用了两个索引数组或由索引数组组成的关联数组。练习的时候,您也许需要采用其他组合。 两个索引数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用两个索引数组时,可以将结果呈示为表或电子表格。第一个数组的元素表示表的行,第二个数组的元素表示表的列。 例如,以下多维数组使用两个索引数组跟踪一周中每一天的任务列表。第一个数组 masterTaskList 是使用 Array 类构造函数创 建的。此数组中的各个元素分别表示一周中的各天,其中索引 0 表示星期一,索引 6 表示星期日。可将这些元素当成是表的 行。可通过为 masterTaskList 数组中创建的七个元素中的每个元素分配数组文本来创建每一天的任务列表。这些数组文本表示 表的列。 var masterTaskList:Array = new Array(); masterTaskList[0] = ["wash dishes", "take out trash"]; masterTaskList[1] = ["wash dishes", "pay bills"]; masterTaskList[2] = ["wash dishes", "dentist", "wash dog"]; masterTaskList[3] = ["wash dishes"]; masterTaskList[4] = ["wash dishes", "clean house"]; masterTaskList[5] = ["wash dishes", "wash car", "pay rent"]; masterTaskList[6] = ["mow lawn", "fix chair"]; 可以使用数组访问 ([]) 运算符访问任意任务列表中的各个项。第一组括号表示一周的某一天,第二组括号表示这一天的任务列 表。例如,若要检索星期三的列表中的第二项任务,请首先使用表示星期三的索引 2,然后使用表示列表中的第二项任务的索 引 1。 trace(masterTaskList[2][1]); // output: dentist 若要检索星期日的列表中的第一项,请使用表示星期日的索引 6 和表示列表中的第一项任务的索引 0。 trace(masterTaskList[6][0]); // output: mow lawn 具有索引数组的关联数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 要使单个数组的访问更加方便,可以使用关联数组表示一周的各天并使用索引数组表示任务列表。通过使用关联数组可以在引 用一周中特定的一天时使用点语法,但要访问关联数组的每个元素还需额外进行运行时处理。以下示例使用关联数组作为任务 列表的基础,并使用键和值对来表示一周中的每一天: var masterTaskList:Object = new Object(); masterTaskList["Monday"] = ["wash dishes", "take out trash"]; masterTaskList["Tuesday"] = ["wash dishes", "pay bills"]; masterTaskList["Wednesday"] = ["wash dishes", "dentist", "wash dog"]; masterTaskList["Thursday"] = ["wash dishes"]; masterTaskList["Friday"] = ["wash dishes", "clean house"]; masterTaskList["Saturday"] = ["wash dishes", "wash car", "pay rent"]; masterTaskList["Sunday"] = ["mow lawn", "fix chair"]; 点语法通过避免使用多组括号改善了代码的可读性。 trace(masterTaskList.Wednesday[1]); // output: dentist trace(masterTaskList.Sunday[0]);// output: mow lawn 可以使用 for..in 循环来遍历任务,但访问与每个键关联的值时必须使用数组访问 ([]) 运算符,而不是点语法。由于 masterTaskList 为关联数组,因而不一定会按照您所期望的顺序检索元素,如以下示例所示:35ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 for (var day:String in masterTaskList) { trace(day + ": " + masterTaskList[day]) } /* output: Sunday: mow lawn,fix chair Wednesday: wash dishes,dentist,wash dog Friday: wash dishes,clean house Thursday: wash dishes Monday: wash dishes,take out trash Saturday: wash dishes,wash car,pay rent Tuesday: wash dishes,pay bills */ 克隆数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Array 类不具有复制数组的内置方法。通过调用不带参数的 concat() 或 slice() 方法,可以创建数组的 “ 浅副本 ”。在浅副本中, 如果原始数组具有对象元素,则仅复制指向对象的引用而非对象本身。与原始数组一样,副本也指向相同的对象。对对象所做 的任何更改都会在两个数组中反映出来。 在 “ 深副本 ” 中,还将复制原始数组中的所有对象,从而使新数组和原始数组指向不同的对象。深度复制需要多行代码,通常 需要创建函数。可以将此类函数作为全局实用程序函数或 Array 子类的方法来进行创建。 以下示例定义一个名为 clone() 的函数以执行深度复制。其算法采用了一般的 Java 编程技巧。此函数创建深副本的方法是:将 数组序列化为 ByteArray 类的实例,然后将此数组读回到新数组中。此函数接受对象,因此既可以将此函数用于索引数组,又 可以将其用于关联数组,如以下代码所示: import flash.utils.ByteArray; function clone(source:Object):* { var myBA:ByteArray = new ByteArray(); myBA.writeObject(source); myBA.position = 0; return(myBA.readObject()); } 扩展 Array 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Array 类是少数不是最终类的核心类之一,也就是说您可以创建自己的 Array 子类。本部分提供了创建 Array 子类的示例,并 讨论了在创建子类过程中会出现的一些问题。 如前所述, ActionScript 中的数组是不能指定数据类型的,但您可以创建只接受具有指定数据类型的元素的 Array 子类。以 下部分中的示例定义名为 TypedArray 的 Array 子类,该子类中的元素限定为具有第一个参数中指定的数据类型的值。这里的 TypedArray 类仅用于说明如何扩展 Array 类,并不一定适用于生产,这有以下若干原因。第一,类型检查是在运行时而非编 译时进行的。第二,当 TypedArray 方法遇到不匹配时,将忽略不匹配并且不会引发异常;当然,修改此方法使其引发异常也 是很简单的。第三,此类无法防止使用数组访问运算符将任一类型的值插入到数组中。第四,其编码风格倾向于简洁而非性能 优化。36ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 注: 可以使用此处介绍的方法创建指定类型的数组。但是,更好的方法是使用 Vector 对象。 Vector 实例是真正的指定类型的 数组,在性能和其他一些方面比 Array 类或任何子类都好。本文所进行的讨论旨在演示如何创建 Array 子类。 声明子类 可以使用 extends 关键字来指示类为 Array 的子类。与 Array 类一样,Array 的子类应使用 dynamic 属性。否则,子类将无法 正常发挥作用。 以下代码显示 TypedArray 类的定义,该类包含一个保存数据类型的常量、一个构造函数方法和四个能够将元素添加到数组的 方法。此示例省略了各方法的代码,但在以后的部分中将列出这些代码并详加说明: public dynamic class TypedArray extends Array { private const dataType:Class; public function TypedArray(...args) {} AS3 override function concat(...args):Array {} AS3 override function push(...args):uint {} AS3 override function splice(...args) {} AS3 override function unshift(...args):uint {} } 由于本示例中假定将编译器选项 -as3 设置为 true,而将编译器选项 -es 设置为 false,因而这四个被覆盖的方法均使用 AS3 命名 空间而非 public 属性。这些是 Adobe Flash Builder 和 Adobe Flash Professional 的默认设置。 如果您是倾向于使用原型继承的高级开发人员,您可能会在以下两个方面对 TypedArray 类进行较小的改动,以使其在编 译器选项 -es 设置为 true 的情况下进行编译。一方面,删除出现的所有 override 属性,并使用 public 属性替换 AS3 命名空 间。另一方面,使用 Array.prototype 替换出现的所有四处 super。 TypedArray 构造函数 由于此子类构造函数必须接受一列任意长度的参数,从而造成了一种有趣的挑战。该挑战就是如何将参数传递给超类构造函数 以创建数组。如果将一列参数作为数组进行传递,则超类构造函数会将其视为 Array 类型的一个参数,并且生成的数组长度始 终只有 1 个元素。传递参数列表的传统处理方式是使用 Function.apply() 方法,此方法将参数数组作为第二个参数,但在执行函 数时将其转换为一列参数。遗憾的是, Function.apply() 方法不能和构造函数一起使用。 剩下的唯一方法是在 TypedArray 构造函数中重新创建 Array 构造函数的逻辑。以下代码说明在 Array 类构造函数中使用的 算法,您可以在 Array 子类构造函数中重复使用此算法:37ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 public dynamic class Array { public function Array(...args) { var n:uint = args.length if (n == 1 && (args[0] is Number)) { var dlen:Number = args[0]; var ulen:uint = dlen; if (ulen != dlen) { throw new RangeError("Array index is not a 32-bit unsigned integer ("+dlen+")"); } length = ulen; } else { length = n; for (var i:int=0; i < n; i++) { this[i] = args[i] } } } } TypedArray 构造函数与 Array 构造函数中的大部分代码都相同,只在四个地方对代码进行了改动。其一,参数列表中新增了 一个必需的 Class 类型参数,使用此参数可以指定数组的数据类型。其二,将传递给构造函数的数据类型分配给 dataType 变 量。其三,在 else 语句中,在 for 循环之后为 length 属性赋值,以使 length 只包括相应类型的参数。其四,for 循环的主体使用 push() 方法的被覆盖版本,以便仅将正确数据类型的参数添加到数组中。以下示例显示 TypedArray 构造函数: public dynamic class TypedArray extends Array { private var dataType:Class; public function TypedArray(typeParam:Class, ...args) { dataType = typeParam; var n:uint = args.length if (n == 1 && (args[0] is Number)) { var dlen:Number = args[0]; var ulen:uint = dlen if (ulen != dlen) { throw new RangeError("Array index is not a 32-bit unsigned integer ("+dlen+")") } length = ulen; } else { for (var i:int=0; i < n; i++) { // type check done in push() this.push(args[i]) } length = this.length; } } }38ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 TypedArray 覆盖的方法 TypedArray 类覆盖前述四种能够将元素添加到数组的方法。在每种情况下,被覆盖方法均添加类型检查,这种检查可以防止 添加不正确数据类型的元素。然后,每种方法均调用其自身的超类版本。 push() 方法使用 for..in 循环来遍历参数列表,并对每个参数执行类型检查。可以使用 splice() 方法,从 args 数组中删除所有不 是正确类型的参数。在 for..in 循环结束后, args 数组仅包含 dataType 类型的值。然后对更新后的 args 数组调用 push() 的超类 版本,如以下代码所示: AS3 override function push(...args):uint { for (var i:* in args) { if (!(args[i] is dataType)) { args.splice(i,1); } } return (super.push.apply(this, args)); } concat() 方法创建一个名为 passArgs 的临时 TypedArray 来存储通过类型检查的参数。这样,便可以重复使用 push() 方法中的 类型检查代码。for..in 循环用于遍历 args 数组,并为每个参数调用 push()。由于将 passArgs 指定为类型 TypedArray,因而将 执行 push() 的 TypedArray 版本。然后, concat() 方法将调用其自身的超类版本,如以下代码所示: AS3 override function concat(...args):Array { var passArgs:TypedArray = new TypedArray(dataType); for (var i:* in args) { // type check done in push() passArgs.push(args[i]); } return (super.concat.apply(this, passArgs)); } splice() 方法使用任意一列参数,但前两个参数始终引用索引号和要删除的元素个数。这就是为什么被覆盖的 splice() 方法仅对 索引位置 2 或其以后的 args 数组元素执行类型检查。该代码中一个有趣的地方是,for 循环中的 splice() 调用看上去似乎是递归 调用,但实际上并不是递归调用,这是由于 args 的类型是 Array 而非 TypedArray,也就是说, args.splice() 调用是对此方法 超类版本的调用。在 for..in 循环结束后,args 数组中将只包含索引位置 2 或其以后位置中具有正确类型的值,并且 splice() 会调 用其自身的超类版本,如下面的代码所示: AS3 override function splice(...args):* { if (args.length > 2) { for (var i:int=2; i< args.length; i++) { if (!(args[i] is dataType)) { args.splice(i,1); } } } return (super.splice.apply(this, args)); } 用于将元素添加到数组开头的 unshift() 方法也可以接受任意一列参数。被覆盖的 unshift() 方法使用的算法与 push() 方法使用的 算法非常类似,如下面的示例代码所示:39ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 AS3 override function unshift(...args):uint { for (var i:* in args) { if (!(args[i] is dataType)) { args.splice(i,1); } } return (super.unshift.apply(this, args)); } } 数组示例:播放列表 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 此 PlayList 示例在管理歌曲列表的音乐播放列表应用程序环境中展示了使用数组的多种技巧。这些方法包括: • 创建索引数组 • 向索引数组中添加项 • 使用不同的排序选项按照不同的属性对对象数组排序 • 将数组转换为以字符分隔的字符串 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在 Samples/PlayList 文件夹中找到 PlayList 应用程序文件。该应用程序包含以下文件: PlayList 类概述 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 PlayList 类管理一组 Song 对象。它具有一些公共方法,可将歌曲添加到播放列表 (addSong() 方法)以及对列表中的歌曲排 序(sortList() 方法)。此外,它还包括一个只读存取器属性 songList,可提供对播放列表中实际歌曲集的访问。在内部, PlayList 类使用私有 Array 变量跟踪其歌曲: 文件 说明 PlayList.mxml 或 PlayList.fla Flash 或 Flex 中的主应用程序文件 (分别为 FLA 和 MXML)。 com/example/programmingas3/playlist/PlayList.as 表示歌曲列表的类。该类使用 Array 存储列表,并管理列表项的排序。 com/example/programmingas3/playlist/Song.as 表示一首歌曲信息的值对象。由 PlayList 类管理的项为 Song 实例。 com/example/programmingas3/playlist/SortProperty.as 伪枚举,其可用值代表 Song 类的属性,可以根据这些属性对 Song 对 象列表排序。40ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 public class PlayList { private var _songs:Array; private var _currentSort:SortProperty = null; private var _needToSort:Boolean = false; ... } 除了 PlayList 类用来跟踪其歌曲列表的 _songs Array 变量以外,还有另外两个私有变量,分别用来跟踪是否需要对列表排序 (_needToSort) 以及在给定时间对列表进行排序所依据的属性 (_currentSort)。 跟所有对象一样,声明 Array 实例只做了创建 Array 工作的一半。在访问 Array 实例的属性或方法之前,必须在 PlayList 类 的构造函数中完成对该实例的实例化。 public function PlayList() { this._songs = new Array(); // Set the initial sorting. this.sortList(SortProperty.TITLE); } 该构造函数的第一行用于实例化 _songs 变量,以使其处于待用状态。此外,还会调用 sortList() 方法来设置初始排序所依据的 属性。 向列表中添加歌曲 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 用户在应用程序中输入新歌曲后,数据条目表单上的代码将调用 PlayList 类的 addSong() 方法。 /** * Adds a song to the playlist. */ public function addSong(song:Song):void { this._songs.push(song); this._needToSort = true; } 在 addSong() 内,将调用 _songs 数组的 push() 方法,以便将传递给 addSong() 的 Song 对象添加为该数组中的新元素。不管之 前应用的是哪种排序方法,使用 push() 方法时,都会将新元素添加到数组末尾。也就是说,调用 push() 方法后,歌曲列表的排 序很可能不正确,因此将 _needToSort 变量设置为 true。理论上说,可以立即调用 sortList() 方法,而无需跟踪是否要在给定时 间对列表进行排序。实际上,不需要立即对歌曲列表排序,除非要对其进行检索。通过延迟排序操作,应用程序不会执行不必 要的排序,例如,在将几首歌曲添加到列表中且不需要立即对其进行检索时。 对歌曲列表排序 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 由于由 PlayList 管理的 Song 实例为复杂对象,因而此应用程序的用户可能要根据不同的属性 (例如,歌曲名称或发行年份) 来对播放列表排序。在 PlayList 应用程序中,对歌曲列表排序的任务由以下三部分组成:确定列表排序所依据的属性,指出按 照该属性排序时应使用的排序操作,以及执行实际排序操作。 排序属性 Song 对象跟踪若干属性,包括歌曲名称、歌手、发行年份、文件名和用户选择的歌曲所属流派。在这些属性当中,只有前三 个可用于排序。为了方便开发人员,此示例中包括 SortProperty 类,此类与枚举作用相同,其值表示可用于排序的属性。41ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 public static const TITLE:SortProperty = new SortProperty("title"); public static const ARTIST:SortProperty = new SortProperty("artist"); public static const YEAR:SortProperty = new SortProperty("year"); SortProperty 类包含 TITLE、ARTIST 和 YEAR 三个常量,其中的每个常量都存储一个字符串,该字符串中包含可用于排序的 相关 Song 类属性的实际名称。在代码的其余部分,只要指示排序属性,都是使用枚举成员完成的。例如,在 PlayList 构造函 数中,最初通过调用 sortList() 方法对列表排序,如下所示: // Set the initial sorting. this.sortList(SortProperty.TITLE); 由于将排序属性指定为 SortProperty.TITLE,因而将根据歌曲名称对歌曲排序。 依据属性排序和指定排序选项 对歌曲列表排序的实际工作是由 PlayList 类在 sortList() 方法中进行的,如下所示: /** * Sorts the list of songs according to the specified property. */ public function sortList(sortProperty:SortProperty):void { ... var sortOptions:uint; switch (sortProperty) { case SortProperty.TITLE: sortOptions = Array.CASEINSENSITIVE; break; case SortProperty.ARTIST: sortOptions = Array.CASEINSENSITIVE; break; case SortProperty.YEAR: sortOptions = Array.NUMERIC; break; } // Perform the actual sorting of the data. this._songs.sortOn(sortProperty.propertyName, sortOptions); // Save the current sort property. this._currentSort = sortProperty; // Record that the list is sorted. this._needToSort = false; } 如果根据歌名或歌手排序,则应按照字母顺序排序;若要根据年份排序,则按照数字顺序排序最为合理。 switch 语句用于根据 sortProperty 参数中指定的值定义合适的排序选项,此选项将存储在 sortOptions 变量中。这里,再次使用命名的枚举成员而非 硬编码值来区分不同属性。 确定排序属性和排序选项之后,将通过调用 sortOn() 方法并将上述两个值作为参数传递来完成对 _songs 数组的排序。对歌曲列 表进行排序之后,记录当前排序属性。 将数组元素组合为以字符分隔的字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在本示例中,数组除了用于在 PlayList 类中维护歌曲列表以外,还用于在 Song 类中帮助管理指定歌曲所属的流派的列表。请 考虑 Song 类定义中的以下代码片断:42ACTIONSCRIPT 3.0 开发人员指南 使用数组 上次更新 2014/12/1 private var _genres:String; public function Song(title:String, artist:String, year:uint, filename:String, genres:Array) { ... // Genres are passed in as an array // but stored as a semicolon-separated string. this._genres = genres.join(";"); } 创建新 Song 实例时,会将用于指定歌曲所属流派的 genres 参数定义为 Array 实例。这有助于将多个流派组合为一个可以传递 给构造函数的变量。但在内部,Song 类在 _genres 私有变量中以分号分隔的 String 实例形式来保存流派。通过调用 join() 方法 (使用文本字符串值 ";" 作为指定分隔符), Array 参数将转换为以分号分隔的字符串。 通过使用相同的标记, genres 存取器可将流派作为 Array 进行设置或检索: public function get genres():Array { // Genres are stored as a semicolon-separated String, // so they need to be transformed into an Array to pass them back out. return this._genres.split(";"); } public function set genres(value:Array):void { // Genres are passed in as an array, // but stored as a semicolon-separated string. this._genres = value.join(";"); } genresset 存取器的行为与构造函数完全相同;它接受 Array 并调用 join() 方法以将其转换为以分号分隔的 String。 get 存取器 执行相反的操作:调用 _genres 变量的 split() 方法,使用指定分隔符 (采用与前面相同的文本字符串值 ";")将 String 拆分为值 数组。43 上次更新 2014/12/1 第 4 章 : 处理错误 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 “ 处理 ” 错误意味着您在自己的应用程序中构建逻辑来响应或修复错误。当编译应用程序时,或编译的应用程序正在运行时, 可能会生成错误。应用程序在处理错误时,当遇到错误时会出现某种响应,而不是没有响应 (当任何导致错误的进程在无提示 的情况下失败时)。正确使用错误处理有助于防止应用程序和应用程序的使用者执行其他意外行为。 不过,错误处理涵盖的内容很广,它包括对编译期间或应用程序运行时引发的许多种错误予以响应。此讨论主要介绍在 ActionScript 3.0 环境中,如何处理运行时错误 (在应用程序运行时引发的错误)、可能生成的不同类型的错误以及错误处理 系统的优点。 错误处理基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 运行时错误是指阻止 ActionScript 内容按预期运行的 ActionScript 代码错误。要确保用户可以顺利运行您的 ActionScript 代码,请在应用程序中编写可以处理错误的代码,该代码可以修复、解决错误,或者至少可以让用户了解已发生了此问题。此 过程称为 “ 错误处理 ”。 错误处理涵盖的内容很广,它包括对编译期间或应用程序运行时引发的许多种错误予以响应。在编译时出现的错误通常比较容 易识别 — 您只需修正这些错误即可完成创建 SWF 文件的过程。 运行时错误可能更难于检测,因为必须实际运行错误代码才会发生这些错误。如果程序片断包含几个代码分支(如 if..then..else 语句),利用实际用户可能使用的所有可能的输入值测试每种可能的情况,以确认代码没有错误。 运行时错误可以分为以下两类:“ 程序错误 ” 是指 ActionScript 代码中的错误,如为方法参数指定了错误的数据类型; “ 逻辑 错误 ” 是指程序的逻辑 (数据检查和值处理)错误,如在银行业应用程序中使用错误的公式来计算利率。同样,通过事先仔细 地测试应用程序,通常可以检测到并纠正这两种类型的错误。 理想情况下,您希望在将应用程序发布到最终用户之前找出并消除其中的所有错误。但是,并非所有错误都是可以预见或避免 的。例如,假设您的 ActionScript 应用程序是从您无法控制的特定网站加载信息。如果该网站在某一时刻不可用,则依赖于该 外部数据的应用程序部分将无法正确运行。错误处理的最重要方面包括应对这些未知情况并妥善进行处理。用户需要继续使用 您的应用程序,或者至少获得一条友好的错误消息来解释应用程序为什么无法运行。 ActionScript 使用以下两种方式来表示运行时错误: • 错误类:很多错误都具有一个关联的错误类。当发生错误时,Flash 运行时 (如 Flash Player 或 Adobe AIR)将创建与该 错误关联的特定错误类的实例。代码可以使用该错误对象中包含的信息对错误进行相应的响应。 • 错误事件:有时,当 Flash 运行时正常触发事件时,也会发生错误。在这类情况下,触发的是错误事件。每个错误事件都有 一个与之关联的类, Flash 运行时会将该类的实例传递给订阅了该错误事件的方法。 要确定特定方法是否会触发错误或错误事件,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中该方法的条目。 重要概念和术语 以下参考列表包含与错误处理例程编程相关的重要术语: 异步 不提供即时结果的程序命令 (如方法调用),而是以事件形式提供结果(或错误)。 捕捉 当异常 (一种运行时错误)发生时,代码识别了该异常,则表示该代码 “ 捕捉 ” 了异常。捕获异常后, Flash 运行时会停 止通知其他 ActionScript 代码发生了异常。44ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 调试器版本 Flash 运行时的特殊版本 (例如 Flash Player 调试器版本或 AIR Debug Launcher (ADL)),其中包含通知用户 发生运行时错误的代码。在 Flash Player 或 Adobe AIR 标准版(大多数用户使用的版本)中,将忽略 ActionScript 代码未处 理的错误。在 Adobe Flash CS4 Professional 和 Adobe Flash Builder 提供的调试器版本中,当出现未处理的错误时,会出现 警告消息。 异常 在应用程序运行时发生的错误, Flash 运行时无法自行解决此问题。 重新引发 当代码捕捉到异常时, Flash 运行时不再通知其他对象发生了异常。如果让其他对象收到发生异常的消息很重要,则 代码必须重新引发异常才能再次启动通知进程。 同步 可提供即时结果 (或立即引发错误)的程序命令 (例如方法调用),这意味着此响应可以在同一代码块使用。 引发 通知 Flash 运行时 (并因此通知其他对象和 ActionScript 代码)发生了错误的行为称为 “ 引发 ” 错误。 错误类型 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 开发和运行应用程序时,您会遇到不同类型的错误和错误术语。下面列出了主要的错误类型和术语: • 编译时错误,这类错误在代码编译期间由 ActionScript 编译器引发。当代码中的语法问题导致应用程序无法生成时即会发 生编译时错误。 • 运行时错误,这类错误在应用程序编译之后运行时发生。运行时错误指在 Flash 运行时 (如 Adobe Flash Player 或 Adobe AIR)中播放 SWF 文件时产生的错误。大多数情况下,您会在出现运行时错误时处理这些错误,将错误报告给用 户,并采取相应的步骤让应用程序继续运行。如果遇到的错误是致命错误,例如无法连接到远程网站或无法加载所需的数 据,您可以使用错误处理让应用程序顺利地完成运行。 • 同步错误是在调用函数时发生的运行时错误 — 例如,当您尝试使用特定方法但传递到该方法的参数无效时, Flash 运行时 会引发异常。多数错误都是在语句执行时同步发生,并且控制流会立即传递给最适用的 catch 语句。 例如,以下代码将会引发一个运行时错误,原因是在程序试图上载文件之前没有调用 browse() 方法: var fileRef:FileReference = new FileReference(); try { fileRef.upload(new URLRequest("http://www.yourdomain.com/fileupload.cfm")); } catch (error:IllegalOperationError) { trace(error); // Error #2037: Functions called in incorrect sequence, or earlier // call was unsuccessful. } 在本例中,将同步引发一个运行时错误,原因是 Flash Player 断定在试图上载文件之前没有调用 browse() 方法。 有关同步错误处理的详细信息,请参阅第 47 页的 “ 在应用程序中处理同步错误 ”。 • 异步错误是发生在正常程序流之外的运行时错误。这些错误可生成事件,而事件侦听器可对其进行捕获。在异步操作中,函 数发起操作但并不等待操作完成。您可以创建错误事件侦听器,以等待应用程序或用户尝试某操作。如果操作失败,则使用 事件侦听器捕捉错误并响应错误事件。然后,该事件侦听器调用一个事件处理函数,以便通过一种有益的方式来响应错误事 件。例如,事件处理函数可以启动一个对话框,以提示用户解决该错误。 下面以前面提到的文件上载同步错误为例。如果在文件上载开始之前成功调用了 browse() 方法,则 Flash Player 会调度若 干个事件。例如,上载开始时,将调度 open 事件。文件上载操作成功完成时,将调度 complete 事件。由于事件处理是异步 进行的 (即,不在特定、已知、预先指定的时间发生),因此使用 addEventListener() 方法可以侦听这些特定的事件,如以 下代码所示:45ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 var fileRef:FileReference = new FileReference(); fileRef.addEventListener(Event.SELECT, selectHandler); fileRef.addEventListener(Event.OPEN, openHandler); fileRef.addEventListener(Event.COMPLETE, completeHandler); fileRef.browse(); function selectHandler(event:Event):void { trace("...select..."); var request:URLRequest = new URLRequest("http://www.yourdomain.com/fileupload.cfm"); request.method = URLRequestMethod.POST; event.target.upload(request); } function openHandler(event:Event):void { trace("...open..."); } function completeHandler(event:Event):void { trace("...complete..."); } 有关异步错误处理的详细信息,请参阅第 52 页的 “ 响应错误事件和状态 ”。 • 未捕获的异常,这类错误在引发后并没有相应的逻辑 (如 catch 语句)来响应它。应用程序引发错误后,如果在当前级别 或更高级别找不到适当的 catch 语句或事件处理函数来处理错误,则认为该错误是未捕获的异常。 如果出现未捕获的错误,运行时会调度 uncaughtError 事件。此事件也称为 “ 全局错误处理程序 ”。 SWF 的 UncaughtErrorEvents 对象调度此事件,可通过 LoaderInfo.uncaughtErrorEvents 属性获得该对象。如果没有为 uncaughtError 事件注册任何侦听器,只要未捕获的错误不停止 SWF,运行时就会忽略未捕获的错误并尝试继续运行。 除调度 uncaughtError 事件之外,Flash 运行时的调试器版本将通过终止当前脚本来响应未捕获的错误。然后,在 trace 语句 输出中显示未捕获的错误,或将错误消息写入日志文件。如果异常对象为 Error 类的实例或其子类之一,则输出中也显示堆 栈跟踪信息。有关使用 Flash 运行时调试版的详细信息,请参阅第 47 页的 “ 使用 Flash 运行时的调试版 ”。 注: 处理 uncaughtError 事件时,如果错误事件由 uncaughtError 事件处理函数引发,该事件处理函数将被多次调用。这 将导致异常的无限循环。建议您避免这样的情况出现。 ActionScript 3.0 中的错误处理 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 由于许多应用程序在没有构建错误处理逻辑的情况下也可以运行,因此开发人员往往会拖延在其应用程序中构建错误处理逻 辑。但如果没有错误处理逻辑,应用程序很容易终止运行,或因某一操作无法按预期执行而让用户感到烦恼。 ActionScript 2.0 具有一个 Error 类,可用来在自定义函数中构建逻辑,以便引发具有特定消息的异常。由于错误处理对于构建用户友好的 应用程序至关重要,因此 ActionScript 3.0 提供了一个扩展的体系结构用来捕获错误。 注: 虽然用于 Adobe Flash Platform 的 ActionScript 3.0 参考中记录了许多方法引发的异常,但不可能包括每种方法可能引 发的所有异常。对于某个方法,即使方法描述中确实列出了它可能引发的某些异常,但仍可能存在方法描述中未明确阐述的语 法错误或其他问题而引发的异常。46ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 ActionScript 3.0 错误处理的构成元素 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 提供了许多用来进行错误处理的工具,其中包括: • 错误类。 ActionScript 3.0 中包括大量 Error 类,扩展了可产生错误对象的情形范围。每个错误类都可以帮助应用程序处 理和响应特定的错误条件,无论这些错误条件是与系统错误相关 (如 MemoryError 条件)、与代码编写错误相关(如 ArgumentError 条件)、与网络和通信错误相关(如 URIError 条件),还是与其他情形相关。有关每个类的详细信息, 请参阅第 55 页的 “ 比较错误类 ”。 • 更少的无提示失败。在 Flash Player 以前的版本中,只有明确使用了 throw 语句,才会产生并报告错误。对于 Flash Player 9 和最新的 Flash 运行时,本机 ActionScript 方法和属性会引发运行时错误。这些错误允许您更有效处理发生的异 常,然后逐个响应每个异常。 • 在调试期间显示清楚的错误消息。使用 Flash 运行时调试器版本时,有问题的代码或情形会生成可靠的错误消息,这有助于 您轻松识别特定代码块失败的原因。这些消息有助于更高效地修复错误。有关详细信息,请参阅第 47 页的 “ 使用 Flash 运 行时的调试版 ”。 • 精确的错误指示可以向用户显示清楚的错误消息。在 Flash Player 的先前版本中,如果 upload() 调用不成功,则 FileReference.upload() 方法会返回布尔值 false,表示发生了五个可能错误中的一种。如果在 ActionScript 3.0 中调用 upload() 方法时出错,四个特有的错误有助于向最终用户显示更准确的错误消息。 • 经过优化完善的错误处理。一些明显的错误是由许多常见原因引发的。例如,在 ActionScript 2.0 中,在填充 FileReference 对象之前, name 属性的值为 null (因此,在您可以使用或显示 name 属性前,请确保已将此值设置为 null 之外的值)。在 ActionScript 3.0 中,如果在填充 name 属性之前试图访问该属性, Flash Player 或 AIR 将引发 IllegalOperationError,通知您尚未设定该值,这时您可以使用 try..catch..finally 块来处理该错误。有关详细信息,请参阅 第 47 页的 “ 使用 try..catch..finally 语句 ”。 • 没有明显的性能缺点。与以前的 ActionScript 版本相比,使用 try..catch..finally 块仅占用很少的额外资源或根本不占用任何 额外资源。 • 允许针对特定异步错误事件构建侦听器的 ErrorEvent 类。有关详细信息,请参阅第 52 页的 “ 响应错误事件和状态 ”。 错误处理策略 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 只要应用程序未遇到会导致问题的情况,则即使未在程序代码中构建错误处理逻辑,应用程序仍然可以成功运行。但是,如果 您没有主动处理错误,并且应用程序确实遇到了问题,用户在应用程序失败时将无从知道原因所在。 在应用程序中进行错误处理有几种不同的方式。下面概括介绍三种主要的错误处理方式: • 使用 try..catch..finally 语句。这些语句可以在发生同步错误时捕捉这些错误。可以将语句嵌套在一个层次中,以便在不同的 代码执行级别捕获异常。有关详细信息,请参阅第 47 页的 “ 使用 try..catch..finally 语句 ”。 • 创建您自己的自定义错误对象。您可以使用 Error 类创建您自己的自定义错误对象,以便跟踪应用程序中内置错误类型未 涵盖的特定操作。然后,您可以对自定义错误对象使用 try..catch..finally 语句。有关详细信息,请参阅第 51 页的 “ 创建自 定义错误类 ”。 • 编写用以响应错误事件的事件侦听器和处理函数。使用此策略,您可以创建全局错误处理程序以处理类似事件,而无需在 try..catch..finally 代码块中复制许多代码。您还可以使用此方法来捕获异步错误。有关详细信息,请参阅第 52 页的 “ 响应错 误事件和状态 ”。47ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 使用 Flash 运行时的调试版 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Adobe 为开发人员提供了一个特殊版本的 Flash 运行时来帮助进行调试。安装 Adobe Flash Professional 或 Adobe Flash Builder 后,您可以获得一个 Flash Player 调试版。在安装其中任一工具时,您还可以获得用于调试 Adobe AIR 应用程序的实 用工具 (该工具称为 ADL),该工具也包含在 Adobe AIR SDK 中。 Flash Player 和 Adobe AIR 的调试版与发行版在错误指示方面有明显的不同。调试版显示错误类型(如一般错误、IOError 或 EOFError)、错误编号和可读错误消息。发行版则仅显示错误类型和错误编号。例如,请看以下代码: try { tf.text = myByteArray.readBoolean(); } catch (error:EOFError) { tf.text = error.toString(); } 如果 readBoolean() 方法在 Flash Player 调试器版本中引发 EOFError,将在 tf 文本字段中显示下列消息:“EOFError: 错误 : #2030: 已到文件尾 ”。) 同样的代码在 Flash Player 或 Adobe AIR 的发行版中则会显示以下文字:“EOFError: 错误 #2030。 ” 注: 调试器播放器将广播名为 “allComplete” 的事件;避免使用名称 “allComplete” 创建自定义事件。否则,您在调试时会遇 到不可预测的行为。 为了使资源和大小在发行版中达到最小,因此未提供错误消息字符串。您可以在文档 (用于 Adobe Flash Platform 的 ActionScript 3.0 参考的附录)中查找与错误消息关联的错误编号。或者,也可以使用 Flash Player 和 AIR 调试版重现错误以 查看完整的错误消息。 在应用程序中处理同步错误 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 最常见的错误处理是同步错误处理逻辑,您可以在处理逻辑中将适当的语句插入代码,以便在应用程序运行时捕获同步错误。 这种错误处理可以让应用程序在功能失败时注意到发生运行时错误并从错误中恢复。同步错误捕获逻辑包括 try..catch..finally 语 句,从字面意义上看,这种方式先尝试 (try) 某个操作,然后捕获 (catch) 来自 Flash 运行时的任何错误响应,最后 (finally) 执 行另外的操作来处理失败的操作。 使用 try..catch..finally 语句 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 处理同步运行时错误时,可以使用 try..catch..finally 语句来捕获错误。当发生运行时错误时, Flash 运行时将引发异常,这意味 着它将暂停正常的操作而创建一个 Error 类型的特殊对象。 Error 对象随后会被引发到第一个可用的 catch 块。 try 语句将有可能产生错误的语句括在一起。catch 语句应始终与 try 语句一起使用。如果在 try 语句块的其中一个语句中检测到 错误,则将运行附加到该 try 语句的 catch 语句。 finally 语句中包含无论 try 块中是否出错均会运行的语句。如果没有错误, finally 块中的语句将在 try 语句块执行完毕之后执 行。如果有错误,则首先执行相应的 catch 语句,然后执行 finally 块中的语句。 48ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 以下代码说明了使用 try..catch..finally 语句的语法: try { // some code that could throw an error } catch (err:Error) { // code to react to the error } finally { // Code that runs whether an error was thrown. This code can clean // up after the error, or take steps to keep the application running. } 每个 catch 语句识别它要处理的特定类型的异常。 catch 语句指定的错误类只能是 Error 类的子类。将按顺序检查每个 catch 语 句。只运行与所引发的错误类型匹配的第一个 catch 语句。换句话说,如果您首先检查更高级别的 Error 类,然后检查 Error 类的子类,则只有更高级别的 Error 类匹配。以下代码说明了这一点: try { throw new ArgumentError("I am an ArgumentError"); } catch (error:Error) { trace(" " + error.message); } catch (error:ArgumentError) { trace(" " + error.message); } 上面这段代码的输出如下: I am an ArgumentError 为正确捕获 ArgumentError,请确保首先列出最具体的错误类型,然后再列出较为一般的错误类型,如以下代码所示: try { throw new ArgumentError("I am an ArgumentError"); } catch (error:ArgumentError) { trace(" " + error.message); } catch (error:Error) { trace(" " + error.message); } ActionScript API 中有几种方法和属性,如果在执行时它们遇到错误,便会引发运行时错误。例如, Sound 类中的 close() 方 法,它如果无法关闭音频流,便会引发 IOError 错误,如以下代码所示: var mySound:Sound = new Sound(); try { mySound.close(); } catch (error:IOError) { // Error #2029: This URLStream object does not have an open stream. }49ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 随着对用于 Adobe Flash Platform 的 ActionScript 3.0 参考的逐渐熟悉,您会发现哪些方法会引发异常。详见每个方法的说 明。 throw 语句 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如果 Flash 运行时在应用程序运行时遇到错误,便会引发异常。此外,您也可以自己使用 throw 语句明确引发异常。如果是明 确引发错误,Adobe 建议您引发 Error 类或其子类的实例。以下代码所展示的 throw 语句引发一个 Error 类实例 MyErr,并且 最后调用一个函数 myFunction() 在引发错误之后进行响应: var MyError:Error = new Error("Encountered an error with the numUsers value", 99); var numUsers:uint = 0; try { if (numUsers == 0) { trace("numUsers equals 0"); } } catch (error:uint) { throw MyError; // Catch unsigned integer errors. } catch (error:int) { throw MyError; // Catch integer errors. } catch (error:Number) { throw MyError; // Catch number errors. } catch (error:*) { throw MyError; // Catch any other error. } finally { myFunction(); // Perform any necessary cleanup here. } 请注意,catch 语句进行了排序,以便先列出最具体的数据类型。如果首先列出的是 Number 数据类型的 catch 语句,则 uint 数据类型和 int 数据类型的 catch 语句均不会运行。 注: 在 Java 编程语言中,每个可以引发异常的函数都必须先声明这一点,并在附加到函数声明的 throw 子句中列出该函数可以 引发的异常类。 ActionScript 不要求您声明由函数引发的异常。 显示简单错误消息 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 新的异常和错误事件模型的一个最大优点就是:它可以让您向用户告知操作失败的时间和原因。您的工作是编写用来显示消息 的代码和在响应中提供选项。 以下代码使用一个简单的 try..catch 语句在一个文本字段中显示错误:50ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 package { import flash.display.Sprite; import flash.text.TextField; public class SimpleError extends Sprite { public var employee:XML = 1234 1-234 ; public function SimpleError() { try { if (employee.costCenter.length() != 1) { throw new Error("Error, employee must have exactly one cost center assigned."); } } catch (error:Error) { var errorMessage:TextField = new TextField(); errorMessage.autoSize = TextFieldAutoSize.LEFT; errorMessage.textColor = 0xFF0000; errorMessage.text = error.message; addChild(errorMessage); } } } } 与 ActionScript 的先前版本相比, ActionScript 3.0 使用了更加丰富的错误类和内置编译器错误,因此可以提供有关失败原 因的更多信息。通过此信息,您可以构建更加稳定且具有更佳错误处理能力的应用程序。 重新引发错误 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 构建应用程序时,有时候,如果无法正确处理错误,则需要重新引发该错误。例如,以下代码使用一个嵌套的 try..catch 块,它 在嵌套的 catch 块无法处理错误时重新引发一个自定义的 ApplicationError:51ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 try { try { trace("<< try >>"); throw new ApplicationError("some error which will be rethrown"); } catch (error:ApplicationError) { trace("<< catch >> " + error); trace("<< throw >>"); throw error; } catch (error:Error) { trace("<< Error >> " + error); } } catch (error:ApplicationError) { trace("<< catch >> " + error); } 上面这个代码片断的输出如下: << try >> << catch >> ApplicationError: some error which will be rethrown << throw >> << catch >> ApplicationError: some error which will be rethrown 嵌套的 try 块引发一个自定义的 ApplicationError 错误,该错误由后续 catch 块捕获。此嵌套的 catch 块会尝试处理错误,如 果不成功,则将 ApplicationError 对象引发到包含此 catch 块的 try..catch 块中来进行处理。 创建自定义错误类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 您可以通过扩展其中一种标准的错误类,在 ActionScript 中创建您自己的专用错误类。有多种原因需要创建您自己的错误类: • 识别应用程序特有的错误或错误组。 例如,除由 Flash 运行时捕获的那些错误外,您还可以采取其他操作来处理由自己的代码引发的错误。您可以创建 Error 类 的一个子类,以便在 try..catch 块中跟踪新的错误数据类型。 • 为应用程序生成的错误提供特有的错误显示能力。 例如,可以创建一个以某种方式设置错误消息格式的新的 toString() 方法。还可以定义一个 lookupErrorString() 方法,该方 法获取错误代码并根据用户的语言首选参数查找适当的消息。 专用的错误类必须扩展 ActionScript 的核心错误类。以下是一个扩展了 Error 类的专用 AppError 类示例: public class AppError extends Error { public function AppError(message:String, errorID:int) { super(message, errorID); } } 以下是在项目中使用 AppError 的一个示例:52ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 try { throw new AppError("Encountered Custom AppError", 29); } catch (error:AppError) { trace(error.errorID + ": " + error.message) } 注: 如果要在子类中覆盖 Error.toString() 方法,请为其提供一个 ... (其余)参数。 ActionScript 3.0 所依据的 ECMAScript 语言规范通过这种方式定义 Error.toString() 方法, ActionScript 3.0 通过同样的方式定义该方法以实现向后兼容。因此,当您 覆盖 Error.toString() 方法时,请与参数完全匹配。在运行时,您不希望将任何参数传递给 toString() 方法,因为这些参数都会 被忽略。 响应错误事件和状态 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 3.0 中,对错误处理最为明显的一项改进就是支持对应用程序运行时出现的异步错误予以响应。(有关异步错 误的定义,请参阅第 44 页的 “ 错误类型 ”。) 可以创建事件侦听器和事件处理函数来响应错误事件。对于许多类来说,它们调度错误事件的方式与调度其他事件的方式相 同。例如,一般情况下, XMLSocket 类实例调度三种类型的事件:Event.CLOSE、Event.CONNECT 和 DataEvent.DATA。但 是,当发生问题时, XMLSocket 类还可以调度 IOErrorEvent.IOError 或 SecurityErrorEvent.SECURITY_ERROR。有关事件侦 听器和事件处理函数的详细信息,请参阅第 106 页的 “ 处理事件 ”。 错误事件分为两类: • 扩展 ErrorEvent 类的错误事件 flash.events.ErrorEvent 类包含用于管理与网络和通信操作 (在运行应用程序中)有关的错误的属性和方法。 AsyncErrorEvent、IOErrorEvent 和 SecurityErrorEvent 类扩展了 ErrorEvent 类。如果您使用的是 Flash 运行时调试 器版本,则会出现一个对话框,向您通知播放器在运行时遇到的没有侦听器函数的任何错误事件。 • 基于状态的错误事件 基于状态的错误事件与网络和通信类的 netStatus 和 status 属性有关。如果 Flash 运行时在读写数据时遇到问题, netStatus.info.level 或 status.level 属性 (取决于使用的类对象)的值将被设置为值 "error"。可以通过检查事件处理函数中的 level 属性是否包含值 "error" 来响应此错误。 使用错误事件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ErrorEvent 类及其子类包含用于处理 Flash 运行时尝试读写数据时调度的错误的错误类型。 下面的示例同时使用了 try..catch 语句和错误事件处理函数来显示在尝试读取本地文件时检测到的任何错误。您可以在由 “ 在此 处添加您的错误处理代码 ” 注释所指示的位置处添加更复杂的处理代码,以便为用户提供处理选项或者自动处理错误:53ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 package { import flash.display.Sprite; import flash.errors.IOError; import flash.events.IOErrorEvent; import flash.events.TextEvent; import flash.media.Sound; import flash.media.SoundChannel; import flash.net.URLRequest; import flash.text.TextField; import flash.text.TextFieldAutoSize; public class LinkEventExample extends Sprite { private var myMP3:Sound; public function LinkEventExample() { myMP3 = new Sound(); var list:TextField = new TextField(); list.autoSize = TextFieldAutoSize.LEFT; list.multiline = true; list.htmlText = "Track 1
"; list.htmlText += "Track 2
"; addEventListener(TextEvent.LINK, linkHandler); addChild(list); } private function playMP3(mp3:String):void { try { myMP3.load(new URLRequest(mp3)); myMP3.play(); } catch (err:Error) { trace(err.message); // your error-handling code here } myMP3.addEventListener(IOErrorEvent.IO_ERROR, errorHandler); } private function linkHandler(linkEvent:TextEvent):void { playMP3(linkEvent.text); // your error-handling code here } private function errorHandler(errorEvent:IOErrorEvent):void { trace(errorEvent.text); // your error-handling code here } } }54ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 使用状态更改事件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 对于支持 level 属性的类, Flash 运行时会在应用程序运行时动态更改 netStatus.info.level 或 status.level 属性的值。具有 netStatus.info.level 属性的类有 NetConnection、 NetStream 和 SharedObject。具有 status.level 属性的类有 HTTPStatusEvent、Camera、Microphone 和 LocalConnection。可以编写一个处理函数来响应 level 值的更改并跟踪通信 错误。 以下示例使用 netStatusHandler() 函数测试 level 属性的值。如果 level 属性指示遇到错误,该代码将跟踪消息 “Video stream failed” (视频流失败)。 package { import flash.display.Sprite; import flash.events.NetStatusEvent; import flash.events.SecurityErrorEvent; import flash.media.Video; import flash.net.NetConnection; import flash.net.NetStream; public class VideoExample extends Sprite { private var videoUrl:String = "Video.flv"; private var connection:NetConnection; private var stream:NetStream; public function VideoExample() { connection = new NetConnection(); connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); connection.connect(null); } private function netStatusHandler(event:NetStatusEvent):void { if (event.info.level == "error") { trace("Video stream failed") } else 55ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 { connectStream(); } } private function securityErrorHandler(event:SecurityErrorEvent):void { trace("securityErrorHandler: " + event); } private function connectStream():void { var stream:NetStream = new NetStream(connection); var video:Video = new Video(); video.attachNetStream(stream); stream.play(videoUrl); addChild(video); } } } 比较错误类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 提供了一些预定义的 Error 类。但您也可以在自己的代码中使用相同的 Error 类。在 ActionScript 3.0 中,有 两种主要类型的错误类:ActionScript 核心错误类和 flash.error 包错误类。 flash.error 包中包含其他有助于 ActionScript 3.0 应用程序进行开发和调试的类。 核心错误类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 核心错误类包括 Error、 ArgumentError、 EvalError、 RangeError、 ReferenceError、 SecurityError、 SyntaxError、 TypeError、 URIError 和 VerifyError 类。其中的每个类均位于顶级命名空间中。 类名称 说明 备注 Error Error 类用于引发异常,并且是 ECMAScript 中定义的 其他异常类的基类,这些异常类包括 EvalError、 RangeError、 ReferenceError、 SyntaxError、 TypeError 和 URIError。 Error 类用作所有运行时错误的基类,并建议将其用作任何自定义错 误类的基类。 ArgumentError ArgumentError 类表示在函数调用期间提供的参数与为 该函数定义的参数不一致时发生的错误。 以下是一些参数错误示例: • 向方法提供的参数过少或过多。 • 参数应是某个枚举值,但实际上不是。 EvalError 如果为 Function 类的构造函数传递了任何参数,或者用 户代码调用 eval() 函数,则会引发 EvalError 异常。 在 ActionScript 3.0 中,已取消对 eval() 函数的支持,并在尝试使用 该函数时出错。 Flash Player 的先前版本使用 eval() 函数来按照名称访问变量、属 性、对象或影片剪辑。 RangeError 如果数值在可接受范围之外,将引发 RangeError 异常。 例如,如果延迟为负或无限,Timer 类就会引发 RangeError。试图 在无效深度处添加显示对象也会引发 RangeError。56ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 flash.error 包 Error 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 flash.error 包中包含的 Error 类被视为 Flash 运行时 API 的一部分。与前面描述的 Error 类不同, flash.error 包与特定于 Flash 运行时 (例如 Flash Player 和 Adobe AIR)的错误事件进行通信。 ReferenceError 如果试图对密封 (非动态)对象引用未定义的属性,则会 引发 ReferenceError 异常。试图访问 undefined 的属性 时, ActionScript 3.0 之前的 ActionScript 编译器版本 并不会引发错误。然而, ActionScript 3.0 在此情况下会 引发 ReferenceError 异常。 由于访问未定义变量而引发异常表明存在潜在的错误,有助于提高软 件质量。但是,如果您不习惯初始化变量,则需要改变一些代码编写 习惯来适应这种新的 ActionScript 行为。 SecurityError 如果发生安全违规且访问被拒绝时,则会引发 SecurityError 异常。 以下是一些安全错误示例: • 通过安全沙箱边界进行未经授权的属性访问或方法调用。 • 尝试访问安全沙箱不允许的 URL。 • 尝试与某个端口进行套接字连接,但是必需的套接字策略文件不 存在。 • 已尝试使用用户的摄像机或麦克风,但用户拒绝了对该设备的使 用。 SyntaxError 如果 ActionScript 代码发生分析错误,则会引发 SyntaxError 异常。 在以下情况下会引发 SyntaxError: • 当 RegExp 类解析无效的正则表达式时, ActionScript 会引发 SyntaxError 异常。 • 当 XMLDocument 类解析无效的 XML 时, ActionScript 会引 发 SyntaxError 异常。 TypeError 如果操作数的实际类型与所需类型不同,则会引发 TypeError 异常。 在以下情况下会引发 TypeError: • 无法将函数的实际参数或方法强制为正式参数类型。 • 值已赋给变量,但无法强制为变量的类型。 • is 或 instanceof 运算符右侧的内容不是有效类型。 • 非法使用了 super 关键字。 • 属性查找生成了多个绑定,因此造成该查找不明确。 • 对不兼容对象调用了某个方法。例如,如果将 RegExp 类中的某 个方法 “ 转接 ” 到通用对象上,然后调用该方法,会引发 TypeError 异常。 URIError 如果采用与某个全局 URI 处理函数的定义相矛盾的方式 使用该函数,则会引发 URIError 异常。 在以下情况下会引发 URIError: 为需要有效 URI 的 Flash Player API 函数 (如 Socket.connect()) 指定了无效的 URI。 VerifyError 如果遇到格式不正确或损坏的 SWF 文件,则会引发 VerifyError 异常。 当 SWF 文件加载另一个 SWF 文件时,父 SWF 文件可以捕获由加 载的 SWF 文件生成的 VerifyError。 类名称 说明 备注57ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 处理错误示例:CustomErrors 应用程序 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 CustomErrors 应用程序展示了构建应用程序时使用自定义错误的一些技巧。这些方法包括: • 验证 XML 包 • 编写自定义错误 • 引发自定义错误 • 引发错误时通知用户 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在 Samples/CustomError 文件夹中找到 CustomErrors 应用程序的文件。该应用程序包含以下文件: 类名称 说明 备注 EOFError 如果尝试读取的内容超出可用数据的末尾,则会引发 EOFError 异常。 例如,当调用 IDataInput 接口中的一个读取方法,而数据 不足以满足读取请求时,将引发 EOFError。 IllegalOperationError 如果方法未实现或者实现中未涵盖当前用法,则会引 发 IllegalOperationError 异常。 以下是非法操作错误异常的示例: • 基类 (如 DisplayObjectContainer)提供的功能比舞 台可以支持的功能多。例如,如果尝试在舞台上获取或设 置遮罩层 (使用 stage.mask), Flash 运行时会引发 IllegalOperationError,并显示消息 “Stage 类不实现此 属性或方法 ”。 • 子类继承了不需要且不想支持的方法。 • 在没有辅助功能支持的情况下编译 Flash Player 之后, 又调用了某些辅助功能方法。 • 从 Flash Player 的运行时版本调用仅创作功能。 • 试图为放在时间轴上的对象设置名称。 IOError 如果发生某种类型的 I/O 异常,则会引发 IOError 异 常。 例如,当试图对尚未连接或已断开连接的套接字进行读 / 写 操作时,将引发此错误。 MemoryError 如果内存分配请求失败,则会引发 MemoryError 异 常。 默认情况下, ActionScript Virtual Machine 2 不会强制 限制 ActionScript 程序所分配的内存大小。在桌面系统 中,内存分配故障并不常见。当系统无法分配操作所需的 内存时,将会看到这样的错误。因此,在桌面系统中,除 非分配请求极大,否则此异常很罕见;例如,分配三十亿 个字节的请求是不可能的,因为 32 位 Microsoft® Windows® 程序仅可以访问 2 GB 的地址空间。 ScriptTimeoutError 如果达到了 15 秒的脚本超时间隔,则会引发 ScriptTimeoutError 异常。通过捕获 ScriptTimeoutError 异常,可以更加妥善地处理脚本 超时。如果没有异常处理函数,则未捕获的异常处理 函数将显示一个带有错误消息的对话框。 为防止恶意开发者捕获这种异常并导致无限循环,仅能够 捕获特定脚本运行过程中引发的第一个 ScriptTimeoutError 异常。随后的 ScriptTimeoutError 异常无法由您的代码捕获,并且立即转至未捕获的异常处 理函数。 StackOverflowError 如果脚本可用堆栈已经用尽,则会引发 StackOverflowError 异常。 StackOverflowError 异常可能指示发生了无限递归。 58ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 CustomErrors 应用程序概述 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当应用程序加载时,将为 Flex 应用程序调用 initApp() 方法,或者为 Flash Professional 应用程序执行时间轴 (非函数)代 码。此代码定义将由 Validator 类验证的示例 XML 包。以下代码运行: employeeXML = John Doe 12345 67890 ; } 稍后,将在舞台上的 TextArea 组件实例中显示该 XML 包。此步骤允许您在尝试重新验证 XML 包之前对其进行修改。 用户单击 Validate 按钮时,将调用 validateData() 方法。该方法使用 Validator 类中的 validateEmployeeXML() 方法来验证员 工 XML 包。以下显示的是 validateData() 方法的代码: function validateData():void { try { var tempXML:XML = XML(xmlText.text); Validator.validateEmployeeXML(tempXML); status.text = "The XML was successfully validated."; } catch (error:FatalError) { showFatalError(error); } catch (error:WarningError) { showWarningError(error); } catch (error:Error) { showGenericError(error); } } 文件 说明 CustomErrors.mxml 或 CustomErrors.fla Flash (FLA) 或 Flex (MXML) 中的主应用程序文件 com/example/programmingas3/errors/ApplicationError.as 一个类,用作 FatalError 类和 WarningError 类的基错误类。 com/example/programmingas3/errors/FatalError.as 用于定义由应用程序引发的 FatalError 错误的类。该类扩展了自定义的 ApplicationError 类。 com/example/programmingas3/errors/Validator.as 一个类,定义了用于验证用户提供的员工 XML 包的单个方法。 com/example/programmingas3/errors/WarningError.as 用于定义由应用程序引发的 WarningError 错误的类。该类扩展了自定义的 ApplicationError 类。59ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 首先,使用 TextArea 组件实例 xmlText 的内容创建一个临时的 XML 对象。接下来,将调用自定义 Validator 类 (com.example.programmingas3/errors/Validator.as) 中的 validateEmployeeXML() 方法,并将临时 XML 对象作为参数传 递。如果这个 XML 包是有效的, Label 组件实例 status 便会显示一条成功消息,然后应用程序退出。如果 validateEmployeeXML() 方法引发了一个自定义错误 (即发生 FatalError、 WarningError 或一般的 Error),则会执行相应 的 catch 语句并调用 showFatalError()、 showWarningError() 或 showGenericError() 方法。这几种方法均会在一个名为 statusText 的文本区域中显示相应的消息,以通知用户发生了特定错误。每个方法还会用具体的消息更新 Label 组件实例 status。 如以下代码所示,如果尝试验证员工 XML 包时发生致命错误,则会在一个 statusText 文本区域中显示错误消息,并且禁用 xmlText TextArea 组件实例和 validateBtn Button 组件实例: function showFatalError(error:FatalError):void { var message:String = error.message + "\n\n"; var title:String = error.getTitle(); statusText.text = message + " " + title + "\n\nThis application has ended."; this.xmlText.enabled = false; this.validateBtn.enabled = false; hideButtons(); } 如果发生的是警告错误而不是致命错误,则会在 statusText TextArea 实例中显示错误消息,但不会禁用 xmlText TextField 和 Button 组件实例。showWarningError() 方法会在 statusText 文本区域中显示自定义的错误消息。该消息还要求用户决定是希望 继续验证 XML 还是取消脚本。以下节选的内容显示的是 showWarningError() 方法代码: function showWarningError(error:WarningError):void { var message:String = error.message + "\n\n" + "Do you want to exit this application?"; showButtons(); var title:String = error.getTitle(); statusText.text = message; } 当用户单击 “ 是 ” 或 “ 否 ” 按钮时,将调用 closeHandler() 方法。以下节选的内容显示的是 closeHandler() 方法代码: function closeHandler(event:CloseEvent):void { switch (event.detail) { case yesButton: showFatalError(new FatalError(9999)); break; case noButton: statusText.text = ""; hideButtons(); break; } } 如果用户通过单击 “ 是 ” 选择取消脚本,会引发 FatalError,导致应用程序终止。 构建自定义验证程序 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 自定义的 Validator 类仅包含一个方法 validateEmployeeXML()。validateEmployeeXML() 方法采用一个参数,即 employee,此 参数是您要验证的 XML 包。 validateEmployeeXML() 方法的代码如下所示:60ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 public static function validateEmployeeXML(employee:XML):void { // checks for the integrity of items in the XML if (employee.costCenter.length() < 1) { throw new FatalError(9000); } if (employee.costCenter.length() > 1) { throw new WarningError(9001); } if (employee.ssn.length() != 1) { throw new FatalError(9002); } } 员工必须属于一个 (且只能属于一个)成本中心才能通过验证。如果员工不属于任何成本中心,该方法将引发 FatalError,该 异常将向上冒泡到应用程序主文件中的 validateData() 方法。如果员工属于多个成本中心,则引发 WarningError。该 XML 验 证程序最后检查用户是否只定义了一个社会安全号码 (XML 包中的 ssn 节点)。如果具有不止一个 ssn 节点,则引发 FatalError 错误。 您可以向 validateEmployeeXML() 方法添加其他检查,例如,确保 ssn 节点包含有效编号,或者员工至少定义了一个电话号码 和电子邮件地址,并且两个值均有效。您还可以对该 XML 进行修改,使每个员工具有唯一的 ID 并指定其管理者的 ID。 定义 ApplicationError 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ApplicationError 类用作 FatalError 类和 WarningError 类的基类。ApplicationError 类扩展了 Error 类,并且定义了自 己的自定义方法和属性,其中包括定义一个错误 ID、严重程度以及包含自定义错误代码和消息的 XML 对象。该类还定义了两 个静态常量,它们用于定义每种错误类型的严重程度。 ApplicationError 类的构造函数方法如下所示: public function ApplicationError() { messages = ; } XML 对象中的每个错误节点都包含一个唯一的数值代码和一条错误消息。使用 E4X 可以很容易地通过错误代码查找到相应的 错误消息,如以下 getMessageText() 方法所示:61ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 public function getMessageText(id:int):String { var message:XMLList = messages.error.(@code == id); return message[0].text(); } getMessageText() 方法仅使用一个整数参数 id 并返回一个字符串。该 id 参数就是要查找的错误的错误代码。例如,传递等于 9001 的 id 值将得到错误消息 “Employee must be assigned to only one cost center” (只能为员工指定一个成本中心)。如 果多个错误具有同一错误代码, ActionScript 将只为找到的第一个结果返回错误消息 (所返回 XMLList 对象中的 message[0])。 该类中的下一个方法 getTitle() 不使用任何参数,并返回一个字符串值,其中包含此特定错误的错误 ID。该值用于帮助您轻松 识别在验证 XML 包期间发生的具体错误。以下显示的是 getTitle() 方法的代码: public function getTitle():String { return "Error #" + id; } ApplicationError 类中的最后一个方法是 toString()。该方法覆盖 Error 类中定义的函数,以便您可以自定义错误消息的显 示。该方法将返回一个字符串,用于识别所发生错误的具体编号和消息。 public override function toString():String { return "[APPLICATION ERROR #" + id + "] " + message; } 定义 FatalError 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 FatalError 类扩展了自定义的 ApplicationError 类并定义三个方法:FatalError 构造函数、 getTitle() 和 toString()。第一个 方法 (即 FatalError 构造函数)接受一个整数参数 errorID,并使用 ApplicationError 类中定义的静态常量设置错误的严重 性,另外还调用 ApplicationError 类中的 getMessageText() 方法获取特定错误的错误消息。 FatalError 构造函数如下所示: public function FatalError(errorID:int) { id = errorID; severity = ApplicationError.FATAL; message = getMessageText(errorID); } FatalError 类中的下一个方法 getTitle() 覆盖先前在 ApplicationError 类中定义的 getTitle() 方法,并在标题后面追加文字 “-- FATAL” 以通知用户发生了致命错误。 getTitle() 方法如下所示: public override function getTitle():String { return "Error #" + id + " -- FATAL"; } 该类中的最后一个方法 toString() 覆盖 ApplicationError 类中定义的 toString() 方法。 toString() 方法如下所示: public override function toString():String { return "[FATAL ERROR #" + id + "] " + message; }62ACTIONSCRIPT 3.0 开发人员指南 处理错误 上次更新 2014/12/1 定义 WarningError 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 WarningError 类扩展了 ApplicationError 类,它与 FatalError 类几乎完全相同,只是字符串稍微有些不同,另外它还将错 误严重程度设置为 ApplicationError.WARNING 而不是 ApplicationError.FATAL,如以下代码所示: public function WarningError(errorID:int) { id = errorID; severity = ApplicationError.WARNING; message = super.getMessageText(errorID); }63 上次更新 2014/12/1 第 5 章 : 使用正则表达式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 正则表达式描述用于查找和处理字符串中的匹配文本的模式。正则表达式类似于字符串,但是可以包含特殊代码以描述模式和 重复。例如,下面的正则表达式与以字符 A 开头并且后跟一个或多个连续数字的字符串匹配: /A\d+/ 以下主题描述构建正则表达式所用的基本语法。但是实际上,正则表达式可能非常复杂且具有许多细微差别。您可以从网上或 者书店中找到有关正则表达式的详细资料。切记,不同的编程环境实现正则表达式的方式也不同。 ActionScript 3.0 按照 ECMAScript 第 3 版语言规范 (ECMA-262) 中的定义实现正则表达式。 更多帮助主题 RegExp 正则表达式基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 正则表达式描述字符模式。通常,正则表达式用于验证文本值是否符合特定模式 (例如,验证用户输入的电话号码位数是否正 确),或者替换与特定模式匹配的部分文本值。 正则表达式可能非常简单。例如,假设您要确认特定字符串与 “ABC” 是否匹配,或者要使用某些其他文本替换字符串中出现 的每个 “ABC”。在这种情况下,您可以使用以下正则表达式,它定义了依次包含字母 A、 B 和 C 的模式: /ABC/ 请注意,正则表达式文本是使用正斜杠 (/) 字符界定的。 正则表达式模式也可能非常复杂,有时候表面上看起来晦涩难懂,例如,以下与有效电子邮件地址匹配的表达式: /([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}/ 通常,您使用正则表达式在字符串中搜索模式以及替换字符。在这些情况下,您将创建一个正则表达式对象,并将其作为几个 String 类方法之一的参数。下列 String 类方法将正则表达式作为参数:match()、 replace()、 search() 和 split()。有关这些方法 的详细信息,请参阅第 15 页的 “ 在字符串中查找模式并替换子字符串 ”。 RegExp 类包含以下方法:test() 和 exec()。有关详细信息,请参阅第 75 页的 “ 对字符串使用正则表达式的方法 ”。 重要概念和术语 以下参考列表中包含与此功能相关的重要术语: 转义符 此字符指示应将后面的字符视为元字符,而不是字面字符。在正则表达式语法中,反斜杠字符 (\) 就是转义字符,因此 反斜杠后跟另一个字符是一个特殊代码,而不仅仅是字符本身。 标志 指定有关应如何使用正则表达式模式的一些选项 (如是否区分大写和小写字符)的字符。 元字符 在正则表达式模式中具有特殊含义的字符,与从字面意义上在模式中表示该字符相对。 限定符 一个或多个字符,用于指示应重复模式的某一部分多少次。例如,使用数量表示符来指定美国邮政编码应包含 5 个或 9 个数字。 正则表达式 用于定义字符模式的程序语句,该字符模式可用来确认其他字符串是否与模式匹配或可用来替换部分字符串。64ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 正则表达式语法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 本节介绍了 ActionScript 正则表达式语法的全部元素。正如您所看到的一样,正则表达式可能非常复杂且具有许多细微差别。 您可以从网上或者书店中找到有关正则表达式的详细资料。切记,不同的编程环境实现正则表达式的方式也不同。 ActionScript 3.0 按照 ECMAScript 第 3 版语言规范 (ECMA-262) 中的定义实现正则表达式。 通常,您要使用的正则表达式是与比较复杂的模式匹配,而不是与简单的字符串匹配。例如,下面的正则表达式定义了由字母 A、 B 和 C 依次排列且后跟数字的模式: /ABC\d/ \d 代码表示 “ 任意数字 ”。反斜杠 (\) 字符称为转义字符,它与后面的字符 (在本例中为字母 d)配合使用,在正则表达式中具 有特殊含义。 下面的正则表达式定义了由字母 ABC 后跟任意数目的数字组成的模式 (注意星号): /ABC\d*/ 星号字符 (*) 是 “ 元字符 ”。元字符是在正则表达式中具有特殊含义的字符。星号是一种称为 “ 数量表示符 ” 的特定类型的元字 符,用于定义某个字符或一组字符重复的次数。有关详细信息,请参阅第 68 页的 “ 数量表示符 ”。 除了它的模式外,正则表达式还可以包含标志,用于指定正则表达式的匹配方式。例如,下面的正则表达式使用 i 标志指定正 则表达式在匹配字符串中忽略大小写: /ABC\d*/i 有关详细信息,请参阅第 72 页的 “ 标志和属性 ”。 您可以通过以下 String 类方法使用正则表达式:match()、 replace() 和 search()。有关这些方法的详细信息,请参阅第 15 页的 “ 在字符串中查找模式并替换子字符串 ”。 创建正则表达式实例 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 有两种方法可以创建正则表达式实例。一种方法是使用正斜杠字符 (/) 来界定正则表达式,另一种是使用 new 构造函数。例如, 以下两个正则表达式是等效的: var pattern1:RegExp = /bob/i; var pattern2:RegExp = new RegExp("bob", "i"); 正斜杠界定正则表达式的方式与用引号界定字符串文本的方式相同。正斜杠内的正则表达式部分定义 “ 模式 ”。正则表达式还 可以在后一个界定斜杠后包含 “ 标志 ”。这些标志也看作是正则表达式的一部分,但是它们独立于模式。 使用 new 构造函数时,使用两个字符串来定义正则表达式。第一个字符串定义模式,第二个字符串定义标志,如下例所示: var pattern2:RegExp = new RegExp("bob", "i"); 如果在使用正斜杠界定符定义的正则表达式中包含正斜杠,则必须在正斜杠前面加上反斜杠 (\) 转义字符。例如,下面的正则 表达式与模式 1/2 匹配: var pattern:RegExp = /1\/2/; 若要在使用 new 构造函数定义的正则表达式中包含引号,您必须在引号前面加上反斜杠 (\) 转义字符(就像定义任何 String 文 本一样)。例如,下面的正则表达式与模式 eat at "joe's" 匹配: var pattern1:RegExp = new RegExp("eat at \"joe's\"", ""); var pattern2:RegExp = new RegExp('eat at "joe\'s"', "");65ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 请勿在使用正斜杠界定符定义的正则表达式中对引号使用反斜杠转义字符。同样地,不要在使用 new 构造函数定义的正则表达 式中对正斜杠使用转义字符。下列正则表达式是等效的,它们都定义了模式 1/2 "joe's": var pattern1:RegExp = /1\/2 "joe's"/; var pattern2:RegExp = new RegExp("1/2 \"joe's\"", ""); var pattern3:RegExp = new RegExp('1/2 "joe\'s"', ''); 此外,在使用 new 构造函数定义的正则表达式中,若要使用以反斜杠 (\) 字符开头的元序列 (例如,\d,用于匹配任何数字), 请键入两个反斜杠字符: var pattern:RegExp = new RegExp("\\d+", ""); // matches one or more digits 在本实例中您必须键入两个反斜杠字符,因为 RegExp() 构造函数方法的第一个参数是字符串,而在字符串文本中必须键入两个 反斜杠字符才能将其识别为单个反斜杠字符。 后面几节将介绍定义正则表达式模式的语法。 有关标志的详细信息,请参阅第 72 页的 “ 标志和属性 ”。 字符、元字符和元序列 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 最简单的正则表达式是与字符序列匹配的表达式,如以下示例中所示: var pattern:RegExp = /hello/; 但是,下列字符 (称为元字符)在正则表达式中具有特殊含义: ^ $ \ . * + ? ( ) [ ] { } | 例如,下面的正则表达式所匹配的是字母 A 后跟字母 B 的零个或多个实例 (星号元字符指示重复)再跟字母 C: /AB*C/ 在正则表达式模式中包含元字符时若要使其不具有特殊含义,您必须使用反斜杠 (\) 转义字符。例如,下面的正则表达式与顺 序依次为字母 A、字母 B、星号和字母 C 的模式匹配: var pattern:RegExp = /AB\*C/; “ 元序列 ” 与元字符类似,在正则表达式中具有特殊含义。元序列由多个字符组成。以下几节提供了有关使用元字符和元序列 的详细信息。 关于元字符 下表总结了可以在正则表达式中使用的元字符: 元字符 说明 ^ (尖号) 匹配字符串的开头。设置 m (multiline) 标志后,尖号还匹配行的开头 (请参阅第 72 页的 “ 标志和属性 ”)。请注 意,尖号用在字符类的开头时指示符号反转而非字符串的开头。有关详细信息,请参阅第 67 页的 “ 字符类 ”。 $ (美元符号) 匹配字符串的结尾。设置 m (multiline) 标志后,$ 还匹配换行 (\n) 字符前面的位置。有关详细信息,请参阅第 72 页 的 “ 标志和属性 ”。 \ ( 反斜杠 ) 对特殊字符的特殊元字符含义进行转义。 此外,如果要在正则表达式文本中使用正斜杠字符,也要使用反斜杠字符,例如, /1\/2/ 匹配字符 1 后跟正斜杠字符 和字符 2。 . (点) 匹配任意单个字符。 只有设置 s (dotall) 标志时,点才匹配换行字符 (\n)。有关详细信息,请参阅第 72 页的 “ 标志和属性 ”。 66ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 关于元序列 元序列是在正则表达式模式中具有特殊含义的字符序列。下表说明了这些元序列: * (星号) 匹配前面重复零次或多次的项目。 有关详细信息,请参阅第 68 页的 “ 数量表示符 ”。 + (加号) 匹配前面重复一次或多次的项目。 有关详细信息,请参阅第 68 页的 “ 数量表示符 ”。 ? (问号) 匹配前面重复零次或一次的项目。 有关详细信息,请参阅第 68 页的 “ 数量表示符 ”。 ( 和 ) 在正则表达式中定义组。以下情况下使用组: • 限制逻辑 “ 或 ” 字符 | 的范围:/(a|b|c)d/ • 定义数量表示符的范围:/(walla.){1,2}/ • 用在逆向引用中。例如,下面的正则表达式中的 \1 匹配模式的第一个括号组中的匹配内容: • /(\w*) is repeated: \1/ 有关详细信息,请参阅第 70 页的 “ 组 ”。 [ 和 ] 定义字符类,字符类定义单个字符可能的匹配: /[aeiou]/ 匹配所指定字符中的任意一个。 在字符类中,使用连字符 (-) 指定字符的范围: /[A-Z0-9]/ 匹配从 A 到 Z 的大写字母或 0 到 9 的数字。 在字符类中,插入反斜杠对 ] 和 - 字符 : /[+\-]\d+/ 匹配一个或多个数字前面的 + 或 -。 在字符类中,以下字符 (通常为元字符)被看作一般字符 (非元字符),不需要反斜杠: /[$]/£ 匹配 $ 或 £。 有关详细信息,请参阅第 67 页的 “ 字符类 ”。 | (竖线) 用于逻辑 “ 或 ” 操作,匹配左侧或右侧的部分: /abc|xyz/ 匹配 abc 或 xyz。 元序列 说明 {n} {n,} 和 {n,n} 指定前一项目的数值数量或数量范围: /A{27}/ 匹配重复 27 次的字符 A。 /A{3,}/ 匹配重复 3 次或更多次的字符 A。 /A{3,5}/ 匹配重复 3 到 5 次的字符 A。 有关详细信息,请参阅第 68 页的 “ 数量表示符 ”。 \b 匹配单词字符和非单词字符之间的位置。如果字符串中的第一个或最后一个字符是单词字符,则也匹配字符串的开 头或结尾。 \B 匹配两个单词字符之间的位置。也匹配两个非单词字符之间的位置。 元字符 说明67ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 字符类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用字符类指定字符列表以匹配正则表达式中的一个位置。使用中括号 ([ 和 ])定义字符类。例如,下面的正则表达式定 义了匹配 bag、 beg、 big、 bog 或 bug 的字符类: /b[aeiou]g/ 字符类中的转义序列 通常在正则表达式中具有特殊含义的大多数元字符和元序列在字符类中 “ 不具有 ” 那些特殊含义。例如,在正则表达式中星号 用于表示重复,但是出现在字符类中时则不具有此含义。下列字符类匹配星号本身以及列出的任何其他字符: /[abc*123]/ 但是,下表中列出的三个字符功能与元字符相同,在字符类中具有特殊含义: 对于要识别为字面字符 (无特殊元字符含义)的任何字符,必须在该字符前面加反斜杠转义字符。例如,下面的正则表达式包 含匹配四个符号 ($、 \、 ] 或 -)中任意一个符号的字符类。 /[$\\\]\-]/ 除能够保持特殊含义的元字符外,下列元序列在字符类中也具有元序列功能: \d 匹配十进制数字。 \D 匹配除数字以外的任何字符。 \f 匹配换页符。 \n 匹配换行符。 \r 匹配回车符。 \s 匹配任何空白字符 (空格、制表符、换行符或回车符)。 \S 匹配除空白字符以外的任何字符。 \t 匹配制表符。 \unnnn 匹配字符代码由十六进制数字 nnnn 指定的 Unicode 字符。例如, \u263a 是一个笑脸字符。 \v 匹配垂直换页符。 \w 匹配单词字符 (A-Z、 a-z、 0-9 或 _)。请注意, \w 不匹配非英文字符,如 é、 ñ 或 ç。 \W 匹配除单词字符以外的任何字符。 \\xnn 匹配具有指定 ASCII 值 (由十六进制数字 nn 定义)的字符。 元字符 在字符类中的含义 ] 定义字符类的结尾。 - 定义字符范围 (请参阅后面的 “ 字符类中字符的范围 ” 一节)。 \ 定义元序列并撤消元字符的特殊含义。 元序列 说明68ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 其他正则表达式元序列和元字符在字符类中看作普通字符。 字符类中字符的范围 使用连字符指定字符的范围,例如 A-Z、 a-z 或 0-9。这些字符必须在字符类中构成有效的范围。例如,下面的字符类匹配 a-z 范围内的任何一个字符或任何数字: /[a-z0-9]/ 您还可以使用 \\xnn ASCII 字符代码通过 ASCII 值指定范围。例如,下面的字符类匹配扩展 ASCII 字符集中的任意字符(如 é 和 ê): \\x 反转的字符类 如果在字符类的开头使用尖号 (^) 字符,则将反转该集合的意义,即未列出的任何字符都认为匹配。下面的字符类匹配除小写 字母 (a-z) 或数字以外的任何字符: /[^a-z0-9]/ 必须在字符类的开头键入尖号 (^) 字符以指示反转。否则,您只是将尖号字符添加到字符类的字符中。例如,下面的字符类匹 配许多符号字符中的任意一个,其中包括尖号: /[!.,#+*%$&^]/ 数量表示符 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用数量表示符指定字符或序列在模式中的重复次数,如下所示: 您可以将数量表示符应用到单个字符、字符类或组: • /a+/ 匹配重复一次或多次的字符 a。 元序列 在字符类中的含义 \n 匹配换行符。 \r 匹配回车符。 \t 匹配制表符。 \unnnn 匹配具有指定 Unicode 代码点值 (由十六进制数字 nnnn 定义)的字符。 \\xnn 匹配具有指定 ASCII 值 (由十六进制数字 nn 定义)的字符。 数量表示符元字符 说明 * (星号) 匹配前面重复零次或多次的项目。 + (加号) 匹配前面重复一次或多次的项目。 ? (问号) 匹配前面重复零次或一次的项目。 {n} {n,} 和 {n,n} 指定前一项目的数值数量或数量范围: /A{27}/ 匹配重复 27 次的字符 A。 /A{3,}/ 匹配重复 3 次或更多次的字符 A。 /A{3,5}/ 匹配重复 3 到 5 次的字符 A。69ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 • /\d+/ 匹配一个或多个数字。 • /[abc]+/ 匹配重复的一个或多个字符,这些字符可能是 a、 b 或 c 中的某个。 • /(very, )*/ 匹配重复零次或多次的后跟逗号和空格的单词 very。 您可以在应用数量表示符的括号组内使用数量表示符。例如,下面的数量表示符匹配诸如 word 和 word-word-word 的字符串: /\w+(-\w+)*/ 默认情况下,正则表达式执行所谓的 “ 无限匹配 ”。正则表达式中的任何子模式 (如 .*)都会尝试在字符串中匹配尽可能多的 字符,然后再执行正则表达式的下一部分。例如,使用以下正则表达式和字符串: var pattern:RegExp = /

.*<\/p>/; str:String = "

Paragraph 1

Paragraph 2

"; 正则表达式匹配整个字符串:

Paragraph 1

Paragraph 2

但是,假如您只想匹配一个

...

组。则可以通过以下操作实现:

Paragraph 1

在所有数量表示符后添加问号 (?) 以将其更改为所谓的 “ 惰性数量表示符 ”。例如,下面的正则表达式使用惰性数量表示符 *? 匹配

后跟数量最少 (惰性)的字符,再跟

的模式: /

.*?<\/p>/ 有关数量表示符,请牢记以下几点: • 数量表示符 {0} 和 {0,0} 不会从匹配中排除项目。 • 不要结合使用多个数量表示符,例如 /abc+*/ 中。 • 在除非设置 s (dotall) 标志,否则不会跨越多行,即使后跟 * 数量表示符。例如,请看以下代码: var str:String = "

Test\n"; str += "Multiline

"; var re:RegExp = /

.*<\/p>/; trace(str.match(re)); // null; re = /

.*<\/p>/s; trace(str.match(re)); // output:

Test // Multiline

有关详细信息,请参阅第 72 页的 “ 标志和属性 ”。 逻辑 “ 或 ” Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在正则表达式中使用 |(竖线)字符可使正则表达式引擎考虑其他匹配。例如,下面的正则表达式匹配单词 cat、dog、pig 和 rat 中的任意一个: var pattern:RegExp = /cat|dog|pig|rat/; 您可以使用括号定义组以限制逻辑 “ 或 ” 字符 | 的范围。下面的正则表达式匹配 cat 后跟 nap 或 nip: var pattern:RegExp = /cat(nap|nip)/; 有关详细信息,请参阅第 70 页的 “ 组 ”。 下面两个正则表达式是等效的,一个使用 | 逻辑 “ 或 ” 字符,另一个使用字符类 (由 [ 和 ] 定义):70ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 /1|3|5|7|9/ /[13579]/ 有关详细信息,请参阅第 67 页的 “ 字符类 ”。 组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 您可以使用括号在正则表达式中指定组,如下所示: /class-(\d*)/ 组是模式的子部分。您可以使用组实现以下操作: • 将数量表示符应用到多个字符。 • 界定要应用逻辑 “ 或 ” (通过使用 | 字符)的子模式。 • 捕获正则表达式中的子字符串匹配(例如,在正则表达式中使用 \1 以匹配先前匹配的组,或类似地在 String 类的 replace() 方法中使用 $1)。 下面几节将介绍有关这些组用法的详细信息。 使用带数量表示符的组 如果不使用组,数量表示符将应用到它前面的字符或字符类,如下所示: var pattern:RegExp = /ab*/ ; // matches the character a followed by // zero or more occurrences of the character b pattern = /a\d+/; // matches the character a followed by // one or more digits pattern = /a[123]{1,3}/; // matches the character a followed by // one to three occurrences of either 1, 2, or 3 然而,您可以使用组将数量表示符应用到多个字符或字符类: var pattern:RegExp = /(ab)*/; // matches zero or more occurrences of the character a // followed by the character b, such as ababab pattern = /(a\d)+/; // matches one or more occurrences of the character a followed by // a digit, such as a1a5a8a3 pattern = /(spam ){1,3}/; // matches 1 to 3 occurrences of the word spam followed by a space 有关数量表示符的详细信息,请参阅第 68 页的 “ 数量表示符 ”。 使用带逻辑 “ 或 ” 字符 (|) 的组 可以使用组来定义一组要应用逻辑 “ 或 ” 字符 (|) 的字符,如下所示: var pattern:RegExp = /cat|dog/; // matches cat or dog pattern = /ca(t|d)og/; // matches catog or cadog71ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 使用组捕获子字符串匹配 如果您在模式中定义标准括号组,则之后可以在正则表达式中引用它。这称为 “ 逆向引用 ”,并且此类型的组称为 “ 捕获组 ”。 例如,在下面的正则表达式中,序列 \1 匹配在捕获括号组中匹配的任意子字符串: var pattern:RegExp = /(\d+)-by-\1/; // matches the following: 48-by-48 您可以通过键入 \1、 \2、 ...、 \99 在正则表达式中最多指定 99 个此类逆向引用。 类似地,在 String 类的 replace() 方法中,可以使用 $1-$99 在替换字符串中插入捕获的组子字符串匹配: var pattern:RegExp = /Hi, (\w+)\./; var str:String = "Hi, Bob."; trace(str.replace(pattern, "$1, hello.")); // output: Bob, hello. 此外,如果使用捕获组, RegExp 类的 exec() 方法和 String 类的 match() 方法将返回与捕获组匹配的子字符串: var pattern:RegExp = /(\w+)@(\w+).(\w+)/; var str:String = "bob@example.com"; trace(pattern.exec(str)); // bob@example.com,bob,example,com 使用非捕获组和向前查找组 非捕获组是只用于分组的组,它不会被 “ 收集 ”,也不会匹配有限的逆向引用。可以使用 (?: 和 ) 来定义非捕获组,如下所示: var pattern = /(?:com|org|net); 例如,注意在捕获组和非捕获组中加入 (com|org) 的区别 (exec() 方法在完全匹配后列出捕获组): var pattern:RegExp = /(\w+)@(\w+).(com|org)/; var str:String = "bob@example.com"; trace(pattern.exec(str)); // bob@example.com,bob,example,com //noncapturing: var pattern:RegExp = /(\w+)@(\w+).(?:com|org)/; var str:String = "bob@example.com"; trace(pattern.exec(str)); // bob@example.com,bob,example 一类特殊的非捕获组是 “ 向前查找组 ”,它包括两种类型:“ 正向前查找组 ” 和 “ 负向前查找组 ”。 使用 (?= 和 ) 定义正向前查找组,它指定组中的子模式位置必须匹配。但是,匹配正向前查找组的字符串部分可能匹配正则表 达式中的剩余模式。例如,由于 (?=e) 在下面的代码中是正向前查找组,它匹配的字符 e 可以被正则表达式的后续部分匹配,在 本例中为捕获组 \w*): var pattern:RegExp = /sh(?=e)(\w*)/i; var str:String = "Shelly sells seashells by the seashore"; trace(pattern.exec(str)); // Shelly,elly 使用 (?! 和 ) 定义负向前查找组,它指定该组中的子模式位置不得匹配。例如: var pattern:RegExp = /sh(?!e)(\w*)/i; var str:String = "She sells seashells by the seashore"; trace(pattern.exec(str)); // shore,ore 使用命名组 命名组是正则表达式中给定命名标识符的一类组。使用 (?P 和 ) 可定义命名组。例如,下面的正则表达式包含标识符命 名为 digits 的命名组: var pattern = /[a-z]+(?P\d+)[a-z]+/;72ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 如果使用 exec() 方法,将添加一个匹配的命名组作为 result 数组属性: var myPattern:RegExp = /([a-z]+)(?P\d+)[a-z]+/; var str:String = "a123bcd"; var result:Array = myPattern.exec(str); trace(result.digits); // 123 这里还有一个例子,它使用两个命名组,标识符分别为 name 和 dom: var emailPattern:RegExp = /(?P(\w|[_.\-])+)@(?P((\w|-)+))+\.\w{2,4}+/; var address:String = "bob@example.com"; var result:Array = emailPattern.exec(address); trace(result.name); // bob trace(result.dom); // example 注: 命名组不属于 ECMAScript 语言规范。它们是 ActionScript 3.0 中的新增功能。 标志和属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 下表列出了可以为正则表达式设置的五种标志。每种标志都可以作为正则表达式对象属性进行访问。 请注意这些属性都是只读属性。您在设置正则表达式变量时,可以设置标志 (g、 i、 m、 s 和 x),如下所示: var re:RegExp = /abc/gimsx; 但是,您无法直接设置命名属性。例如,下列代码将导致错误: var re:RegExp = /abc/; re.global = true; // This generates an error. 默认情况下,除非您在正则表达式声明中指定这些标志,否则不会设置,并且相应的属性也会设置为 false。 另外,还有其他两种正则表达式属性: • lastIndex 属性指定字符串中的索引位置以用于下次调用正则表达式的 exec() 或 test() 方法。 • source 属性指定定义正则表达式的模式部分的字符串。 g (global) 标志 如果不包含 g (global) 标志,正则表达式匹配将不超过一个。例如,如果正则表达式中不包含 g 标志, String.match() 方法只返 回一个匹配的子字符串: var str:String = "she sells seashells by the seashore."; var pattern:RegExp = /sh\w*/; trace(str.match(pattern)) // output: she 如果设置 g 标志, Sting.match() 方法将返回多个匹配,如下所示: 标志 属性 说明 g global 匹配多个匹配。 i ignoreCase 不区分大小写的匹配。应用于 A-Z 和 a-z 字符,但不能应用于扩展字符,如 É 和 é。 m multiline 设置此标志后, $ 和 ^ 可以分别匹配行的开头和结尾。 s dotall 设置此标志后, . (点)可以匹配换行符 (\n)。 x extended 允许扩展的正则表达式。您可以在正则表达式中键入空格,它将作为模式的一部分被忽略。这可使您更加清晰可 读地键入正则表达式代码。73ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 var str:String = "she sells seashells by the seashore."; var pattern:RegExp = /sh\w*/g; // The same pattern, but this time the g flag IS set. trace(str.match(pattern)); // output: she,shells,shore i (ignoreCase) 标志 默认情况下,正则表达式匹配区分大小写。如果设置 i (ignoreCase) 标志,将忽略区分大小写。例如,正则表达式中的小写字母 s 不会匹配大写字母 S (字符串中的第一个字符): var str:String = "She sells seashells by the seashore."; trace(str.search(/sh/)); // output: 13 -- Not the first character 但是如果设置 i 标志,正则表达式将匹配大写字母 S: var str:String = "She sells seashells by the seashore."; trace(str.search(/sh/i)); // output: 0 i 标志仅忽略 A-Z 和 a-z 字符的大小写,而不忽略扩展字符的大小写,如 É 和 é。 m (multiline) 标志 如果没有设置 m (multiline) 标志,^ 将匹配字符串的开头,而 $ 匹配字符串的结尾。如果设置 m 标志,这些字符将分别匹配行 的开头和结尾。请考虑使用下列包含换行符的字符串: var str:String = "Test\n"; str += "Multiline"; trace(str.match(/^\w*/g)); // Match a word at the beginning of the string. 即使在正则表达式中设置 g (global) 标志, match() 方法也会只匹配一个子字符串,因为对于 ^ (字符串开头)只有一个匹配。 输出结果为: Test 下面是设置了 m 标志的同一段代码: var str:String = "Test\n"; str += "Multiline"; trace(str.match(/^\w*/gm)); // Match a word at the beginning of lines. 这次输出结果同时包含两行开头的单词: Test,Multiline 请注意,只有 \n 字符表示行的结束。下列字符不表示行的结束: • 回车 (\r) 字符 • Unicode 行分隔符 (\u2028) 字符 • Unicode 段分隔符 (\u2029) 字符 s (dotall) 标志 如果没有设置 s (dotall 或 “dot all”)标志,则正则表达式中的点 (.) 将不匹配换行符 (\n)。因此,下面的示例没有匹配: var str:String = "

Test\n"; str += "Multiline

"; var re:RegExp = /

.*?<\/p>/; trace(str.match(re)); 但是,如果设置了 s 标志,点就匹配换行符: var str:String = "

Test\n"; str += "Multiline

"; var re:RegExp = /

.*?<\/p>/s; trace(str.match(re)); 74ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 在本例中,匹配内容是

标签内的整个子字符串,其中包括换行符:

Test Multiline

x (extended) 标志 正则表达式有时很难阅读,特别是当其包含很多元字符和元序列时。例如: /|(\s*[^>]*>)).*?<\/p>/gi 在正则表达式中使用 x (extended) 标志时,则会忽略在模式中键入的所有空格。例如,下面的正则表达式同前面的示例相同: /

| (\s* [^>]* >)) .*? <\/p> /gix 如果设置了 x 标志,而且希望匹配空格字符,则应在空格前加上反斜杠。例如,以下两个正则表达式是等效的: /foo bar/ /foo \ bar/x lastIndex 属性 lastIndex 属性在字符串中指定开始进行下一次搜索的索引位置。对于将 g 标志设置为 true 的正则表达式,此属性会影响对该表 达式调用的 exec() 和 test() 方法。例如,请看以下代码: var pattern:RegExp = /p\w*/gi; var str:String = "Pedro Piper picked a peck of pickled peppers."; trace(pattern.lastIndex); var result:Object = pattern.exec(str); while (result != null) { trace(pattern.lastIndex); result = pattern.exec(str); } 默认情况下, lastIndex 属性设置为 0 (从字符串的开头开始搜索)。每次匹配完成后,都会设为该匹配后的索引位置。因此, 前面代码的输出如下所示: 0 5 11 18 25 36 44 如果将 global 标志设置为 false,则 exec() 和 test() 方法不会使用或设置 lastIndex 属性。 String 类的 match()、 replace() 和 search() 方法都从字符串的开头进行搜索,而不考虑调用该方法时所使用的正则表达式中的 lastIndex 属性设置。(但是, match() 方法不会将 lastIndex 设为 0。) 可以设置 lastIndex 属性来调整字符串中的起始位置以对正则表达式进行匹配。 source 属性 source 属性指定用于定义正则表达式的模式部分的字符串。例如: var pattern:RegExp = /foo/gi; trace(pattern.source); // foo75ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 对字符串使用正则表达式的方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 RegExp 类包含两个方法:exec() 和 test()。 除 RegExp 类的 exec() 和 test() 方法外, String 类还包含以下方法,使您可以在字符串中匹配正则表达式:match()、 replace()、 search() 和 splice()。 test() 方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 RegExp 类的 test() 方法只检查提供的字符串是否包含正则表达式的匹配内容,如下面的示例所示: var pattern:RegExp = /Class-\w/; var str = "Class-A"; trace(pattern.test(str)); // output: true exec() 方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 RegExp 类的 exec() 方法检查提供的字符串是否有正则表达式的匹配,并返回具有如下内容的数组: • 匹配的子字符串 • 同正则表达式中的任意括号组匹配的子字符串 该数组还包含 index 属性,此属性指明子字符串匹配起始的索引位置。 例如,请看以下代码: var pattern:RegExp = /\d{3}\-\d{3}-\d{4}/; //U.S phone number var str:String = "phone: 415-555-1212"; var result:Array = pattern.exec(str); trace(result.index, " - ", result); // 7-415-555-1212 在正则表达式设置了 g (global) 标志时,多次使用 exec() 方法可以匹配多个子字符串: var pattern:RegExp = /\w*sh\w*/gi; var str:String = "She sells seashells by the seashore"; var result:Array = pattern.exec(str); while (result != null) { trace(result.index, "\t", pattern.lastIndex, "\t", result); result = pattern.exec(str); } //output: // 0 3 She // 10 19 seashells // 27 35 seashore76ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 使用 RegExp 参数的 String 方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 下列 String 类方法将正则表达式作为参数:match()、replace()、search() 和 split()。有关这些方法的详细信息,请参阅第 15 页 的 “ 在字符串中查找模式并替换子字符串 ”。 正则表达式示例:Wiki 解析程序 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 这个简单的 Wiki 文本转换示例说明了正则表达式的一些用途: • 将与源 Wiki 模式匹配的文本行转换为相应的 HTML 输出字符串。 • 使用正则表达式将 URL 模式转换为 HTML 超链接标签。 • 使用正则表达式将美元符号字符串 (如 "$9.95")转换为欧元符号字符串 (如 "8.24 €")。 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。 WikiEditor 应用程序文件位于文件夹 Samples/WikiEditor 中。该应用程序包含以下文件: 定义 WikiParser 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 WikiParser 类包含将 Wiki 输入文本转换为等效 HTML 输出的方法。它虽然不是功能非常强大的 Wiki 转换应用程序,但是 说明了正则表达式在模式匹配和字符串转换方面的一些很好的用法。 构造函数和 setWikiData() 方法一起,可简单地初始化 Wiki 输入文本范例字符串,如下所示: public function WikiParser() { wikiData = setWikiData(); } 当用户单击范例应用程序中的 “Test” 按钮时,应用程序将调用 WikiParser 对象的 parseWikiString() 方法。此方法可调用许多 其他方法,这些方法再组合输出的 HTML 字符串。 文件 说明 WikiEditor.mxml 或 WikiEditor.fla Flash 或 Flex 中的主应用程序文件 (分别为 FLA 和 MXML)。 com/example/programmingas3/regExpExamples/WikiParser.as 该类包含使用正则表达式将 Wiki 输入文本模式转换为等效 HTML 输出的方法。 com/example/programmingas3/regExpExamples/URLParser.as 该类包含使用正则表达式将 URL 字符串转换为 HTML 超 链接标签的方法。 com/example/programmingas3/regExpExamples/CurrencyConverter.as 该类包含使用正则表达式将美元符号字符串转换为欧元符号字 符串的方法。77ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 public function parseWikiString(wikiString:String):String { var result:String = parseBold(wikiString); result = parseItalic(result); result = linesToParagraphs(result); result = parseBullets(result); return result; } 所调用的每个方法 (parseBold()、parseItalic()、linesToParagraphs() 和 parseBullets())都会使用字符串的 replace() 方法替换由 正则表达式定义的匹配模式,以便将 Wiki 输入文本转换为 HTML 格式的文本。 转换粗体和斜体模式。 parseBold() 方法会查找 Wiki 粗体文本模式 (如 '''foo''')并将其转换为等效的 HTML 格式 (如 foo),如下所示: private function parseBold(input:String):String { var pattern:RegExp = /'''(.*?)'''/g; return input.replace(pattern, "$1"); } 请注意,正则表达式的 (.?*) 部分匹配两个定义 ''' 模式之间任意数目的字符 (*)。? 数量表示符使匹配不再是无限制的,因此对于 字符串 '''aaa''' bbb '''ccc''',第一个匹配的字符串是 '''aaa''' 而不是以 ''' 模式开头和结尾的整个字符串。 正则表达式中的括号定义捕获组, replace() 方法通过在替换字符串中使用 $1 代码引用此组。正则表达式中的 g (global) 标志确 保 replace() 方法替换字符串中的所有匹配 (不仅仅是第一个)。 parseItalic() 方法的原理与 parseBold() 方法类似,只是前者检查作为斜体文本分隔符的两个省略号 ('') (而不是三个): private function parseItalic(input:String):String { var pattern:RegExp = /''(.*?)''/g; return input.replace(pattern, "$1"); } 转换项目符号模式 如下面的示例所示, parseBullet() 方法会查找 Wiki 项目符号行模式 (如 * foo)并将其转换为等效的 HTML 格式 (如

  • foo
  • ): private function parseBullets(input:String):String { var pattern:RegExp = /^\*(.*)/gm; return input.replace(pattern, "
  • $1
  • "); } 正则表达式开头的 ^ 符号匹配行的开头。正则表达式中的 m (multiline) 标志使正则表达式用 ^ 符号来匹配行的开头,而不是简 单地匹配字符串的开头。 \* 模式匹配星号字符 (反斜杠用于表示星号本身,而不是 * 数量表示符)。 正则表达式中的括号定义捕获组, replace() 方法通过在替换字符串中使用 $1 代码引用此组。正则表达式中的 g (global) 标志确 保 replace() 方法替换字符串中的所有匹配 (不仅仅是第一个)。 转换段落 Wiki 模式 linesToParagraphs() 方法将每行中输入的 Wiki 字符串转换为 HTML

    段落标签。该方法中的这些行从输入的 Wiki 字符串 中去除空行: var pattern:RegExp = /^$/gm; var result:String = input.replace(pattern, "");78ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 正则表达式中的 ^ 和 $ 符号分别匹配行的开头和结尾。正则表达式中的 m (multiline) 标志使正则表达式用 ^ 符号来匹配行的开 头,而不是简单地匹配字符串的开头。 replace() 方法使用空字符串 ("") 替换所有匹配子字符串 (空行)。正则表达式中的 g (global) 标志确保 replace() 方法替换字符 串中的所有匹配 (不仅仅是第一个)。 将 URL 转换为 HTML 标签 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当用户单击范例应用程序中的 “Test” 按钮时,如果用户选中了 urlToATag 复选框,应用程序将调用 URLParser.urlToATag() 静 态方法以将 URL 字符串从输入的 Wiki 字符串转换为 HTML 标签。 var protocol:String = "((?:http|ftp)://)"; var urlPart:String = "([a-z0-9_-]+\.[a-z0-9_-]+)"; var optionalUrlPart:String = "(\.[a-z0-9_-]*)"; var urlPattern:RegExp = new RegExp(protocol + urlPart + optionalUrlPart, "ig"); var result:String = input.replace(urlPattern, "$1$2$3"); RegExp() 构造函数用于将各组成部分组合成正则表达式 (urlPattern)。这些组成部分是定义正则表达式模式部分的各个字符串。 由 protocol 字符串定义的正则表达式模式的第一部分定义了 URL 协议:http:// 或 ftp://。括号定义了由 ? 符号指示的非捕获组。 这意味着括号只是用来定义用于 | 逻辑 “ 或 ” 模式的组,该组不会匹配 replace() 方法的替换字符串中的逆向引用代码 ($1、 $2、 $3)。 正则表达式的其他组成部分都会使用捕获组 (由模式中的括号指示),然后用在 replace() 方法的替换字符串中的逆向引用代码 ($1、 $2、 $3)中。 由 urlPart 字符串定义的模式部分至少匹配下列字符中的一个:a-z、0-9、_ 或 -。+ 数量表示符指示至少一个字符匹配。\。 指示 一个必需的点 (.) 字符。其余部分匹配至少包含以下字符中的一个的字符串:a-z、 0-9、 _ 或 -。 由 optionalUrlPart 字符串定义的模式部分匹配零个或多个以下字符:点 (.) 字符后跟任意数目的字母数字字符 (包括 _ 和 -)。 * 数量指示符表明零个或多个字符匹配。 调用 replace() 方法可应用正则表达式,并且使用逆向引用来组合替换 HTML 字符串。 然后 urlToATag() 方法会调用 emailToATag() 方法,后者使用类似的技术用 HTML 超链接字符串替换电子邮件模式。在本 范例文件中用于匹配 HTTP、FTP 和电子邮件 URL 的正则表达式是相当简单的,只是起到示范作用,还有更复杂的正则表达 式更准确地匹配这类 URL。 将美元符号字符串转换为欧元符号字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当用户单击范例应用程序中的 “Test” 按钮时,如果用户选中了 dollarToEuro 复选框,应用程序将调用 CurrencyConverter.usdToEuro() 静态方法以将美元符号字符串 (如 "$9.95")转换为欧元符号字符串 (如 "8.24 €"),如下所 示: var usdPrice:RegExp = /\$([\d,]+.\d+)+/g; return input.replace(usdPrice, usdStrToEuroStr); 第一行定义的简单模式匹配美元符号字符串。请注意, $ 字符前面加反斜杠 (\) 转义字符。 replace() 方法将正则表达式用作模式匹配参数,并调用 usdStrToEuroStr() 函数以确定替换字符串 (欧元值)。 如果将函数名称用作 replace() 方法的第二个参数时,则会将以下内容作为参数传递给被调用的函数: • 字符串的匹配部分。79ACTIONSCRIPT 3.0 开发人员指南 使用正则表达式 上次更新 2014/12/1 • 任何捕获的括号组匹配。按这种方式传递的参数数目因捕获的括号组匹配的数目而异。您可以通过检查函数代码中的 arguments.length - 3 来确定捕获的括号组匹配的数目。 • 字符串中匹配开始的索引位置。 • 完整的字符串。 usdStrToEuroStr() 方法将美元符号字符串模式转换为欧元符号字符串,如下所示: private function usdToEuro(...args):String { var usd:String = args[1]; usd = usd.replace(",", ""); var exchangeRate:Number = 0.828017; var euro:Number = Number(usd) * exchangeRate; trace(usd, Number(usd), euro); const euroSymbol:String = String.fromCharCode(8364); // € return euro.toFixed(2) + " " + euroSymbol; } 请注意,args[1] 表示由 usdPrice 正则表达式匹配的捕获括号组。这是美元符号字符串的数字部分,也就是没有 $ 符号的美元数 目。该方法应用汇率转换并返回生成的字符串 (带有尾随符号 €,而不是前导符号 $)。80 上次更新 2014/12/1 第 6 章 : 使用 XML Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 包含一组基于 ECMAScript for XML (E4X) 规范 (ECMA-357 第 2 版)的类。这些类包含用于使用 XML 数据的强大且易用的功能。与以前的编程技术相比,使用 E4X 可以更快地用 XML 数据开发代码。此外,开发的代码也 更容易阅读。 更多帮助主题 XML 类 ECMA - 357 规范 XML 基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 XML 是一种表示结构化信息的标准方法,以使计算机能够方便地使用此类信息,并且人们可以非常方便地编写和理解这些信 息。 XML 是 eXtensible Markup Language (可扩展标记语言)的缩写。 www.w3.org/XML/ 上提供了 XML 标准。 XML 提供了一种简便的标准方法对数据进行分类,以使其更易于读取、访问以及处理。XML 使用类似于 HTML 的树结构和 标签结构。以下是一个简单的 XML 数据示例: What you know? Steve and the flubberblubs 1989 2006-10-17-08:31 XML 数据也可能会比较复杂,其中包含嵌套在其他标签中的标签以及属性和其他结构组件。以下是一个比较复杂的 XML 数 据示例:81ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 Questions, unanswered Steve and the flubberblubs 1989 What do you know? Steve and the flubberblubs 2006-10-17-08:31 Who do you know? Steve and the flubberblubs 2006-10-17-08:35 When do you know? Steve and the flubberblubs 2006-10-17-08:39 Do you know? Steve and the flubberblubs 2006-10-17-08:44 请注意,此 XML 文档中包含其他完整 XML 结构 (如 song 标签及其子标签)。此文档还说明了其他 XML 结构,如属性 (song 标签中的 tracknumber 和 length)以及包含其他标签而不是包含数据的标签 (如 tracks 标签)。 XML 快速入门 如果您没有或几乎没有 XML 方面的经验,您可以阅读下面对 XML 数据的最常见特性的简要说明。 XML 数据是以纯文本格 式编写的,并使用特定语法将信息组织为结构化格式。通常,将一组 XML 数据称为 “XML 文档 ”。在 XML 格式中,通过分 层结构将数据组织到元素 (可以是单个数据项,也可以是其他元素的容器)中。每个 XML 文档将一个元素作为顶级项目或主 项目;此根元素内可能会包含一条信息,但更可能会包含其他元素,而这些元素又包含其他元素,依此类推。例如,以下 XML 文档包含有关音乐唱片的信息: What do you know? Steve and the flubberblubs Happy 2006-10-17-08:31 每个元素都是用一组标签来区分的,即元素名称括在尖括号 (小于号和大于号)中。开始标签 (指示元素的开头)包含元素名 称: 结束标签 (标记元素的结尾)在元素名称前面包含一个正斜杠: 如果元素不包含任何内容,则会将其编写为一个空元素 (有时称为自结束元素)。在 XML 中,以下元素: 与下面的元素完全相同: 82ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 除了在开始和结束标签之间包含的元素内容外,元素还可以包含在元素开始标签中定义的其他值 (称为属性)。例如,以下 XML 元素定义一个名为 length 且值为 "4:19" 的属性: 每个 XML 元素都包含内容,这可以是单个值、一个或多个 XML 元素或没有任何内容 (对于空元素)。 了解有关 XML 的详细信息 要了解有关使用 XML 的详细信息,请参阅额外的一些书籍和资源以了解有关 XML 的详细信息,其中包括以下 Web 站点: • W3Schools XML 教程:http://w3schools.com/xml/ • XMLpitstop 教程、讨论列表等等:http://xmlpitstop.com/ 用于使用 XML 的 ActionScript 类 ActionScript 3.0 包含一些用于使用 XML 结构化信息的类。下面列出了两个主类: • XML:表示单个 XML 元素,它可以是包含多个子元素的 XML 文档,也可以是文档中的单值元素。 • XMLList:表示一组 XML 元素。当具有多个 “ 同级 ” (在 XML 文档层次中位于相同级别,并且包含在相同父级中)的 XML 元素时,将使用 XMLList 对象。例如,XMLList 实例是使用以下一组 XML 元素(可能包含在 XML 文档中)的最 简便方法: Fred Wilson James Schmidt Susan Harriet Thurndon 对于涉及 XML 命名空间的更高级用法,ActionScript 还包含 Namespace 和 QName 类。有关详细信息,请参阅第 93 页的 “ 使用 XML 命名空间 ”。 除了用于使用 XML 的内置类外, ActionScript 3.0 还包含一些运算符,它们提供了用于访问和使用 XML 数据的特定功能。 这种使用这些类和运算符来使用 XML 的方法称为 ECMAScript for XML (E4X),它是由 ECMA-357 第 2 版规范定义的。 重要概念和术语 以下参考列表包含进行 XML 处理例程编程时会遇到的重要术语: 元素 XML 文档中的单个项目,它被标识为开始标签和结束标签之间包含的内容 (包括标签)。 XML 元素可以包含文本数据 或其他元素,也可以为空。 空元素 不包含任何子元素的 XML 元素。通常,将空元素编写为自结束标签 (如 )。 文档 单个 XML 结构。 XML 文档可以包含任意数量的元素 (或者仅包含单个空元素);但是, XML 文档必须具有一个顶级 元素,该元素包含文档中的所有其他元素。 节点 XML 元素的另一个名称。 属性 与元素关联的命名值,它以 attributename="value" 格式写入到元素的开始标签中,而不是编写为嵌套在元素内的单独子元 素。 用于处理 XML 的 E4X 方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ECMAScript for XML 规范定义了一组用于使用 XML 数据的类和功能。这些类和功能统称为 E4X。ActionScript 3.0 包含 以下 E4X 类:XML、 XMLList、 QName 和 Namespace。83ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 E4X 类的方法、属性和运算符旨在实现以下目标: • 简单 — 在可能的情况下,使用 E4X 可以更容易地编写和理解用于使用 XML 数据的代码。 • 一致 — E4X 背后的方法和推理在内部是一致的,并与 ActionScript 的其他部分保持一致。 • 熟悉 — 使用众所周知的运算符来处理 XML 数据,如点 (.) 运算符。 注: ActionScript 2.0 中有一个不同的 XML 类。在 ActionScript 3.0 中,已将该类重命名为 XMLDocument,以使该名称 不会与作为 E4X 的一部分的 ActionScript 3.0 XML 类冲突。在 ActionScript 3.0 中, flash.xml 包中包含了 XMLDocument、 XMLNode、 XMLParser 和 XMLTag 几个旧类,主要是用于旧支持。新的 E4X 类是核心类;无需导入 包即可使用这些类。有关旧 ActionScript 2.0 XML 类的详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中的 flash.xml 包。 下面是使用 E4X 处理数据的一个示例: var myXML:XML = burger 3.95 fries 1.45 通常,应用程序都会从外部源 (如 Web 服务或 RSS 供给)加载 XML 数据。然而,为清楚起见,此处提供的代码示例将 XML 数据作为文本进行分配。 如下面的代码所示, E4X 包含了一些直观运算符 (如点 (.) 和属性标识符 (@) 运算符),用于访问 XML 中的属性: trace(myXML.item[0].menuName); // Output: burger trace(myXML.item.(@id==2).menuName); // Output: fries trace(myXML.item.(menuName=="burger").price); // Output: 3.95 使用 appendChild() 方法可为 XML 分配新的子节点,如以下代码片断所示: var newItem:XML = medium cola 1.25 myXML.appendChild(newItem); 使用 @ 和 . 运算符不仅可以读取数据,还可以分配数据,如下所示: myXML.item[0].menuName="regular burger"; myXML.item[1].menuName="small fries"; myXML.item[2].menuName="medium cola"; myXML.item.(menuName=="regular burger").@quantity = "2"; myXML.item.(menuName=="small fries").@quantity = "2"; myXML.item.(menuName=="medium cola").@quantity = "2"; 使用 for 循环可以循环访问 XML 的节点,如下所示:84ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 var total:Number = 0; for each (var property:XML in myXML.item) { var q:int = Number(property.@quantity); var p:Number = Number(property.price); var itemTotal:Number = q * p; total += itemTotal; trace(q + " " + property.menuName + " $" + itemTotal.toFixed(2)) } trace("Total: $", total.toFixed(2)); XML 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 XML 对象可能表示 XML 元素、属性、注释、处理指令或文本元素。 XML 对象分为包含简单内容和包含复杂内容两类。有子节点的 XML 对象归入包含复杂内容的一类。如果 XML 对象是属性、 注释、处理指令或文本节点之中的任何一个,我们就说它包含简单内容。 例如,下面的 XML 对象包含复杂内容,包括一条注释和一条处理指令: XML.ignoreComments = false; XML.ignoreProcessingInstructions = false; var x1:XML = burger 3.95 fries 1.45 如下面的示例所示,现在可以使用 comments() 和 processingInstructions() 方法创建新的 XML 对象(一个是注释,一个是处理 指令): var x2:XML = x1.comments()[0]; var x3:XML = x1.processingInstructions()[0]; XML 属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 XML 类有五个静态属性: • ignoreComments 和 ignoreProcessingInstructions 属性确定分析 XML 对象时是否忽略注释或处理指令。 • ignoreWhitespace 属性确定在只由空白字符分隔的元素标签和内嵌表达式中是否忽略空白字符。 • prettyIndent 和 prettyPrinting 属性用于设置由 XML 类的 toString() 和 toXMLString() 方法返回的文本的格式。 有关这些属性的详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考。85ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 XML 方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 以下是 XML 对象的分层结构的使用方法: • appendChild() • child() • childIndex() • children() • descendants() • elements() • insertChildAfter() • insertChildBefore() • parent() • prependChild() 以下方法可与 XML 对象属性一起使用: • attribute() • attributes() 以下方法可与 XML 对象属性一起使用: • hasOwnProperty() • propertyIsEnumerable() • replace() • setChildren() 以下方法用于与限定名和命名空间一起使用: • addNamespace() • inScopeNamespaces() • localName() • name() • namespace() • namespaceDeclarations() • removeNamespace() • setLocalName() • setName() • setNamespace() 以下方法用于使用和确定某些类型的 XML 内容: • comments() • hasComplexContent() • hasSimpleContent()86ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 • nodeKind() • processingInstructions() • text() 以下方法用于转换为字符串和设置 XML 对象的格式: • defaultSettings() • setSettings() • settings() • normalize() • toString() • toXMLString() 另外还有几个方法: • contains() • copy() • valueOf() • length() 有关这些方法的详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考。 XMLList 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 XMLList 实例表示 XML 对象的任意集合。它可以包含完整的 XML 文档、 XML 片断或 XML 查询结果。 以下是 XMLList 对象的分层结构的使用方法: • child() • children() • descendants() • elements() • parent() 以下方法可以与 XMLList 对象属性一起使用: • attribute() • attributes() 以下方法可以与 XMLList 属性一起使用: • hasOwnProperty() • propertyIsEnumerable() 以下方法用于使用和确定某些类型的 XML 内容: • comments() • hasComplexContent()87ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 • hasSimpleContent() • processingInstructions() • text() 以下方法用于转换为字符串和设置 XMLList 对象的格式: • normalize() • toString() • toXMLString() 另外还有几个方法: • contains() • copy() • length() • valueOf() 有关这些方法的详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考。 对于只包含一个 XML 元素的 XMLList 对象,可以使用 XML 类的所有属性和方法,因为包含一个 XML 元素的 XMLList 被 视为等同于 XML 对象。例如,在下面的代码中,因为 doc.div 是包含一个元素的 XMLList 对象,所以可以使用 XML 类的 appendChild() 方法: var doc:XML =

    ; doc.div.appendChild(

    World

    ); 有关 XML 属性和方法的列表,请参阅 第 84 页的 “XML 对象 ”。 初始化 XML 变量 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可将 XML 文本赋予 XML 对象,如下所示: var myXML:XML = burger 3.95 fries 1.45 如下面的代码片断所示,还可以使用 new 构造函数从包含 XML 数据的字符串创建 XML 对象的实例: var str:String = "burger" + "3.95"; var myXML:XML = new XML(str);88ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 如果字符串中的 XML 数据格式有误 (例如缺少结束标签),则会出现运行时错误。 还可以将数据按引用 (从其他变量)传递到 XML 对象,如下面的示例所示: var tagname:String = "item"; var attributename:String = "id"; var attributevalue:String = "5"; var content:String = "Chicken"; var x:XML = <{tagname} {attributename}={attributevalue}>{content}; trace(x.toXMLString()) // Output: Chicken 要从 URL 加载 XML 数据,请使用 URLLoader 类,如下面的示例所示: import flash.events.Event; import flash.net.URLLoader; import flash.net.URLRequest; var externalXML:XML; var loader:URLLoader = new URLLoader(); var request:URLRequest = new URLRequest("xmlFile.xml"); loader.load(request); loader.addEventListener(Event.COMPLETE, onComplete); function onComplete(event:Event):void { var loader:URLLoader = event.target as URLLoader; if (loader != null) { externalXML = new XML(loader.data); trace(externalXML.toXMLString()); } else { trace("loader is not a URLLoader!"); } } 要从套接字连接读取 XML 数据,请使用 XMLSocket 类。有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中的 XMLSocket 类。 组合和变换 XML 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用 prependChild() 方法或 appendChild() 方法可在 XML 对象属性列表的开头或结尾添加属性,如下面的示例所示: var x1:XML =

    Line 1

    var x2:XML =

    Line 2

    var x:XML = x = x.appendChild(x1); x = x.appendChild(x2); x = x.prependChild(

    Line 0

    ); // x ==

    Line 0

    Line 1

    Line 2

    使用 insertChildBefore() 方法或 insertChildAfter() 方法在指定属性之前或之后添加属性,如下所示:89ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 var x:XML =

    Paragraph 1

    Paragraph 2

    var newNode:XML =

    Paragraph 1.5

    x = x.insertChildAfter(x.p[0], newNode) x = x.insertChildBefore(x.p[2],

    Paragraph 1.75

    ) 如下面的示例所示,还可以使用大括号运算符 ({ 和 })在构造 XML 对象时按引用 (从其他变量)传递数据: var ids:Array = [121, 122, 123]; var names:Array = [["Murphy","Pat"], ["Thibaut","Jean"], ["Smith","Vijay"]] var x:XML = new XML(""); for (var i:int = 0; i < 3; i++) { var newnode:XML = new XML(); newnode = {names[i][0]} {names[i][1]} ; x = x.appendChild(newnode) } 可以使用 = 运算符将属性指定给 XML 对象,如下所示: var x:XML = Smith x.firstname = "Jean"; x.@id = "239"; 这将对 XML 对象 x 进行如下设置: Smith Jean 可以使用 + 和 += 运算符连接 XMLList 对象: var x1:XML =
    test1 var x2:XML = test2 var xList:XMLList = x1 + x2; xList += test3 这将对 XMLList 对象 xList 进行如下设置: test1 test2 test3 遍历 XML 结构 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 XML 的一个强大功能是它能够通过文本字符的线性字符串提供复杂的嵌套数据。将数据加载到 XML 对象时, ActionScript 会分析数据并将其分层结构加载到内存 (如果 XML 数据格式有误,它会发送运行时错误)。 90ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 利用 XML 和 XMLList 对象的运算符和方法可以轻松遍历 XML 数据的结构。 使用点 (.) 运算符和后代存取器 (..) 运算符可以访问 XML 对象的子属性。请考虑下面的 XML 对象: var myXML:XML = Baking Extravagant Pastries with Kumquats Contino Chuck 238 Emu Care and Breeding Case Justin 115 对象 myXML.book 是一个 XMLList 对象,它包含名为 book 的 myXML 对象的子属性。它们是两个 XML 对象,与 myXML 对 象的两个 book 属性相匹配。 对象 myXML..lastName 是一个 XMLList 对象,它包含名字为 lastName 的所有后代属性。它们是两个 XML 对象,与 myXML 对象的两个 lastName 相匹配。 myXML.book.editor.lastName 对象是一个 XMLList 对象,它包含 myXML 对象的名为 book 的子对象的名为 editor 的子对象的 名为 lastName 的所有子对象:在本例中, XMLList 对象只包含一个 XML 对象 (值为 "Case" 的 lastName 属性)。 访问父节点和子节点 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 parent() 方法返回 XML 对象的父项。 可以使用子级列表的序数索引值访问特定的子对象。例如,假设 XML 对象 myXML 有两个名为 book 的子属性。每个名为 book 的子属性都有一个与之关联的索引编号: myXML.book[0] myXML.book[1] 若要访问特定的孙项,可为子项和孙项名称同时指定索引编号: myXML.book[0].title[0] 不过,如果 x.book[0] 只有一个名为 title 的子项,则可以省略索引引用,如下所示: myXML.book[0].title 同样,如果对象 x 只有一个 book 子对象,并且该子对象只有一个 title 对象,则可以同时省略两个索引引用,如下所示: myXML.book.title 可以使用 child() 方法导航到名称基于变量或表达式的子项,如下面的示例所示:91ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 var myXML:XML = Dictionary ; var childName:String = "book"; trace(myXML.child(childName).title) // output: Dictionary 访问属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用 @ 符号 (属性标识符运算符)可以访问 XML 或 XMLList 对象的属性,如下面的代码所示: var employee:XML = Wu Erin ; trace(employee.@id); // 6401 可将 * 通配符和 @ 符号一起使用来访问 XML 或 XMLList 对象的所有属性,如下面的代码所示: var employee:XML = Wu Erin ; trace(employee.@*.toXMLString()); // 6401 // 233 可以使用 attribute() 或 attributes() 方法访问 XML 或 XMLList 对象的特定属性或所有属性,如下面的代码所示: var employee:XML = Wu Erin ; trace(employee.attribute("id")); // 6401 trace(employee.attribute("*").toXMLString()); // 6401 // 233 trace(employee.attributes().toXMLString()); // 6401 // 233 请注意,还可以使用以下语法访问属性,如下面的示例所示: employee.attribute("id") employee["@id"] employee.@["id"] 其中每一个都等效于 employee.@id。但是,语法 employee.@id 是首选方式。92ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 按属性或元素值过滤 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用括号运算符 — ( 和 ) — 过滤具有特定元素名称或属性值的元素。请考虑下面的 XML 对象: var x:XML = Zmed Sue Data analyst McGee Chuck Jr. data analyst 以下表达式都是有效的: • x.employee.(lastName == "McGee") — 这是第二个 employee 节点。 • x.employee.(lastName == "McGee").firstName — 这是第二个 employee 节点的 firstName 属性。 • x.employee.(lastName == "McGee").@id — 这是第二个 employee 节点的 id 属性的值。 • x.employee.(@id == 347) — 第一个 employee 节点。 • x.employee.(@id == 347).lastName — 这是第一个 employee 节点的 lastName 属性。 • x.employee.(@id > 300) — 这是具有两个 employee 属性的 XMLList。 • x.employee.(position.toString().search("analyst") > -1) — 这是具有两个 position 属性的 XMLList。 如果您尝试过滤不存在的属性或元素,会引发异常。例如,以下代码的最后一行产生一个错误,因为第二个 p 元素没有 id 属 性: var doc:XML =

    Hello, Bob.

    Hello.

    ; trace(doc.p.(@id == '123')); 同样,以下代码的最后一行也会产生一个错误,因为第二个 p 元素没有 b 属性: var doc:XML =

    Hello, Bob.

    Hello.

    ; trace(doc.p.(b == 'Bob')); 为避免出现这些错误,可以使用 attribute() 和 elements() 方法来识别具有匹配属性或元素的属性,如以下代码所示: var doc:XML =

    Hello, Bob.

    Hello.

    ; trace(doc.p.(attribute('id') == '123')); trace(doc.p.(elements('b') == 'Bob')); 还可以使用 hasOwnProperty() 方法,如下面的代码所示:93ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 var doc:XML =

    Hello, Bob.

    Hello.

    ; trace(doc.p.(hasOwnProperty('@id') && @id == '123')); trace(doc.p.(hasOwnProperty('b') && b == 'Bob')); 使用 for..in 和 for each..in 语句 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 包含 for..in 语句和 for each..in 语句,用于遍历 XMLList 对象。例如,我们来看下面的 XML 对象 myXML 和 XMLList 对象 myXML.item。 XMLList 对象 myXML.item 由 XML 对象的两个 item 节点组成。 var myXML:XML = burger 3.95 fries 1.45 ; for..in 语句用于遍历 XMLList 中的一组属性名称: var total:Number = 0; for (var pname:String in myXML.item) { total += myXML.item.@quantity[pname] * myXML.item.price[pname]; } for each..in 语句用于遍历 XMLList 中的属性: var total2:Number = 0; for each (var prop:XML in myXML.item) { total2 += prop.@quantity * prop.price; } 使用 XML 命名空间 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 XML 对象 (或文档)中的命名空间用于标识对象所包含的数据的类型。例如,在将 XML 数据发送和提交给使用 SOAP 消息 传递协议的 Web 服务时,您要在 XML 的开始标签中声明命名空间: var message:XML = 78 ;94ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 命名空间有一个前缀 soap 和一个定义该命名空间的 URI http://schemas.xmlsoap.org/soap/envelope/。 ActionScript 3.0 包含用于使用 XML 命名空间的命名空间类。对于上一示例中的 XML 对象,可按如下方式使用命名空间 类: var soapNS:Namespace = message.namespace("soap"); trace(soapNS); // Output: http://schemas.xmlsoap.org/soap/envelope/ var wNS:Namespace = new Namespace("w", "http://www.test.com/weather/"); message.addNamespace(wNS); var encodingStyle:XMLList = message.@soapNS::encodingStyle; var body:XMLList = message.soapNS::Body; message.soapNS::Body.wNS::GetWeatherResponse.wNS::tempurature = "78"; XML 类包含下列可与命名空间一起使用的方法:addNamespace()、 inScopeNamespaces()、 localName()、 name()、 namespace()、 namespaceDeclarations()、 removeNamespace()、 setLocalName()、 setName() 和 setNamespace()。 使用 default xml namespace 指令可为 XML 对象指定默认命名空间。例如,在以下代码中,x1 和 x2 具有相同的默认命名空间: var ns1:Namespace = new Namespace("http://www.example.com/namespaces/"); default xml namespace = ns1; var x1:XML = ; var x2:XML = ; XML 类型转换 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以将 XML 对象和 XMLList 对象转换为字符串值。同样,也可以将字符串转换为 XML 对象和 XMLList 对象。还要记住, 所有 XML 属性值、名称和文本值都是字符串。以下几节将讨论所有这些形式的 XML 类型转换。 将 XML 和 XMLList 对象转换为字符串 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 XML 和 XMLList 类都包含 toString() 方法和 toXMLString() 方法。toXMLString() 方法返回一个字符串,其中包含该 XML 对 象的所有标签、属性、命名空间声明和内容。对于包含复杂内容 (子元素)的 XML 对象, toString() 方法的作用与 toXMLString() 方法完全相同。对于包含简单内容的 XML 对象 (只包含一个文本元素的对象), toString() 方法只返回该元素 的文本内容,如下面的示例所示: var myXML:XML = burger 3.95 ; trace(myXML.item[0].menuName.toXMLString()); // burger trace(myXML.item[0].menuName.toString()); // burger 如果使用 trace() 方法但不指定 toString() 或 toXMLString(),则默认情况下将使用 toString() 方法转换数据,如以下代码所示:95ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 var myXML:XML = burger 3.95 ; trace(myXML.item[0].menuName); // burger 使用 trace() 方法调试代码时,通常都希望使用 toXMLString() 方法,以便 trace() 方法输出更完整的数据。 将字符串转换为 XML 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 new XML() 构造函数从字符串创建 XML 对象,如下所示: var x:XML = new XML("test"); 如果试图将表示无效 XML 或格式有误的 XML 的字符串转换为 XML,则会引发运行时错误,如下所示: var x:XML = new XML("test"); // throws an error 从字符串转换属性值、名称和文本值 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 所有 XML 属性值、名称和文本值都是 String 数据类型,可能需要将它们转换为其他数据类型。例如,以下代码使用 Number() 函数将文本值转换为数字: var myXML:XML = 3.95 1.00 ; var total:XML = 0; myXML.appendChild(total); for each (var item:XML in myXML.item) { myXML.total.children()[0] = Number(myXML.total.children()[0]) + Number(item.price.children()[0]); } trace(myXML.total); // 4.95; 如果这些代码不使用 Number() 函数,它们将把 + 运算符解释为字符串连接运算符,最后一行中的 trace() 方法将输出以下结 果: 01.003.9596ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 读取外部 XML 文档 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 URLLoader 类从 URL 加载 XML 数据。若要在您的应用程序中使用以下代码,请将示例中的 XML_URL 值替换为 有效的 URL: import flash.events.Event; import flash.net.URLLoader; var myXML:XML = new XML(); var XML_URL:String = "http://www.example.com/Sample3.xml"; var myXMLURL:URLRequest = new URLRequest(XML_URL); var myLoader:URLLoader = new URLLoader(myXMLURL); myLoader.addEventListener(Event.COMPLETE, xmlLoaded); function xmlLoaded(event:Event):void { myXML = XML(myLoader.data); trace("Data loaded."); } 还可以使用 XMLSocket 类设置与服务器的异步 XML 套接字连接。有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考。 在 ActionScript 中使用 XML 的示例:从 Internet 加载 RSS 数据 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 RSSViewer 范例应用程序说明了在 ActionScript 中使用 XML 的一些功能,其中包括: • 使用 XML 方法以 RSS 供给的形式遍历 XML 数据。 • 使用 XML 方法以 HTML 的形式组合 XML 数据,以便在文本字段中使用。 RSS 格式被广泛用于通过 XML 收集新闻。简单的 RSS 数据文件可能如下所示:97ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 Alaska - Weather http://www.nws.noaa.gov/alerts/ak.html Alaska - Watches, Warnings and Advisories Short Term Forecast - Taiya Inlet, Klondike Highway (Alaska) http://www.nws.noaa.gov/alerts/ak.html#A18.AJKNK.1900 Short Term Forecast Issued At: 2005-04-11T19:00:00 Expired At: 2005-04-12T01:00:00 Issuing Weather Forecast Office Homepage: http://pajk.arh.noaa.gov Short Term Forecast - Haines Borough (Alaska) http://www.nws.noaa.gov/alerts/ak.html#AKZ019.AJKNOWAJK.190000 Short Term Forecast Issued At: 2005-04-11T19:00:00 Expired At: 2005-04-12T01:00:00 Issuing Weather Forecast Office Homepage: http://pajk.arh.noaa.gov SimpleRSS 应用程序从 Internet 上读取 RSS 数据,分析标题、链接和描述的数据,并返回这些数据。 SimpleRSSUI 类提供 了相应的用户界面,并会调用 SimpleRSS 类,从而执行所有 XML 处理。 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。 RSSViewer 应用程序文件位于 Samples/RSSViewer 文件夹中。该应用程序包含以下文件: 文件 说明 RSSViewer.mxml 或 RSSViewer.fla Flash 或 Flex 中的主应用程序文件 (分别为 FLA 和 MXML)。 com/example/programmingas3/rssViewer/RSSParser.as 一个类,包含的方法可以使用 E4X 遍历 RSS (XML) 数据并生成相应的 HTML 表 示形式。 RSSData/ak.rss 一个 RSS 范例文件。该应用程序被设置为从 Web 上由 Adobe 托管的 Flex RSS 供 给处读取 RSS 数据。不过,您也可以轻松更改该应用程序,使之从此文档读取 RSS 数据,此文档所用的架构与 Flex RSS 供给的架构略有不同。98ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 读取和分析 XML 数据 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 RSSParser 类包含一个 xmlLoaded() 方法,该方法可将输入 RSS 数据 (存储在 rssXML 变量中)转换为包含 HTML 格式的输 出 (rssOutput) 的字符串。 如果源 RSS 数据包含默认的命名空间,代码会在此方法的开头附近设置默认的 XML 命名空间: if (rssXML.namespace("") != undefined) { default xml namespace = rssXML.namespace(""); } 下面的几行代码循环访问源 XML 数据的内容,以检查名为 item 的各个后代属性: for each (var item:XML in rssXML..item) { var itemTitle:String = item.title.toString(); var itemDescription:String = item.description.toString(); var itemLink:String = item.link.toString(); outXML += buildItemHTML(itemTitle, itemDescription, itemLink); } 前三行代码只是设置字符串变量,以表示 XML 数据的 item 属性的标题、描述和链接属性。下一行随后调用 buildItemHTML() 方法,以 XMLList 对象形式获取 HTML 数据,并使用三个新的字符串变量作为参数。 组合 XMLList 数据 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 HTML 数据 (XMLList 对象)具有如下形式: itemTitle

    itemDescription
    More...

    方法的第一行清除默认的 XML 命名空间: default xml namespace = new Namespace(); default xml namespace 指令具有函数块级作用域。这意味着此声明的作用域是 buildItemHTML() 方法。 下面的几行代码基于传递给该函数的字符串参数组合 XMLList:99ACTIONSCRIPT 3.0 开发人员指南 使用 XML 上次更新 2014/12/1 var body:XMLList = new XMLList(); body += new XML("" + itemTitle + ""); var p:XML = new XML("

    " + itemDescription + "

    "); var link:XML = ; link.@href = itemLink; // link.font.@color = "#008000"; // // 0x008000 = green link.font = "More..."; p.appendChild(
    ); p.appendChild(link); body += p; 此 XMLList 对象表示适用于 ActionScript HTML 文本字段的字符串数据。 xmlLoaded() 方法使用 buildItemHTML() 方法的返回值并将其转换为字符串: XML.prettyPrinting = false; rssOutput = outXML.toXMLString(); 提取 RSS 源的标题并发送自定义事件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 xmlLoaded() 方法根据源 RSS XML 数据中的信息设置 rssTitle 字符串变量: rssTitle = rssXML.channel.title.toString(); 最后, xmlLoaded() 方法生成一个事件,通知应用程序数据已经过分析并且可用: dataWritten = new Event("dataWritten", true);100 上次更新 2014/12/1 第 7 章 : 使用本机 JSON 功能 ActionScript 3.0 提供了一个本机 API,用于采用 JavaScript Object Notation (JSON) 格式对 ActionScript 对象进行编码 和解码。 JSON 类和支持成员函数遵循 ECMA-262 第 5 版规范,并稍有改动。 社区成员 Todd Anderson 提供了本机 JSON API 与第三方 as3corelib JSON 类的比较。请参阅 在 Flash Player 11 中 使用本机 JSON。 更多帮助主题 JSON JSON API 概述 ActionScript JSON API 由 JSON 类和几个本机类上的 toJSON() 成员函数组成。对于要求任何类提供自定义 JSON 编码的应 用程序, ActionScript 框架将提供覆盖默认编码的方法。 JSON 类内部处理任何不提供 toJSON() 成员的 ActionScript 类的导入和导出。对于此类情况, JSON 将遍历所遇到的每一个 对象的公共属性。如果一个对象包含其他对象, JSON 将以递归形式访问嵌套对象,并执行相同的遍历。如果任何对象提供 toJSON() 方法, JSON 将使用该自定义方法,而不是其内部算法。 JSON 接口包含一个编码方法 stringify() 和一个解码方法 parse()。其中每种方法都提供一个参数,您可以将自己的逻辑插入 JSON 编码和解码工作流程。对于 stringify(),此参数名为 replacer ;对于 parse(),此参数为 reviver。这些参数使用以下签名 通过两个参数来定义函数: function(k, v):* toJSON() 方法 toJSON() 方法的签名为 public function toJSON(k:String):* JSON.stringify() 在遍历对象期间,对遇到的每个公共属性调用 toJSON() (如果存在)。该属性由一个密钥 - 值对组成。当 stringify() 调用 toJSON() 时,它将传入当前检查的属性的密钥 (k)。典型的 toJSON() 实现计算每个属性名称,并采用所需编码 返回其值。 toJSON() 方法可以返回任何类型的值 (用 * 表示),而不仅仅是字符串。此变量返回类型允许 toJSON() 返回一个对象 (如果 适用)。例如,如果您的自定义类的某个属性包含来自其他第三方库中的对象,当 toJSON() 遇到您的属性时,您可以返回该对 象。随后, JSON 以递归形式访问第三方对象。编码处理流的行为如下: • 如果 toJSON() 返回一个计算结果不是字符串的对象,则 stringify() 将以递归形式访问该对象。 • 如果 toJSON() 返回一个字符串,则 stringify() 会将此值包装到另一个字符串中,返回包装后的字符串,然后移到下一个值。 在许多情况下,返回对象操作会优先返回您的应用程序所创建的 JSON 字符串。返回对象操作将充分利用内置 JSON 编码算 法,并且还允许 JSON 以递归形式访问嵌套对象。 toJSON() 方法不是在 Object 类中定义,也不是在大多数其他本地类中定义。如果缺少此方法,则 JSON 必须对对象的公共属 性执行标准遍历。您也可以根据需要使用 toJSON() 来公开对象的私有属性。 不过,有些本地类可能会出现一些问题,因为 ActionScript 库不能有效地解决所有使用案例。对于这些类, ActionScript 提 供一个简单实现,客户端可以重新实现以满足其需求。提供普通 toJSON() 成员的类包括: • ByteArray101ACTIONSCRIPT 3.0 开发人员指南 使用本机 JSON 功能 上次更新 2014/12/1 • Date • Dictionary • XML 您可以使 ByteArray 类子类化以覆盖其 toJSON() 方法,或者您也可以重新定义其原型。最后声明的 Date 和 XML 类要求使用 类原型来重新定义 toJSON()。 Dictionary 类声明为动态类,您可以使用该类随时覆盖 toJSON()。 定义自定义 JSON 行为 如果要对本地类实施您自己的 JSON 编码和解码,则可以选择以下几个选项: • 定义或覆盖非最终本地类的自定义子类上的 toJSON() • 定义或重新定义类原型上的 toJSON() • 定义动态类上的 toJSON 属性 • 使用 JSON.stringify() replacer 和 JSON.parser() reviver 参数 更多帮助主题 ECMA-262,第 5 版 在内置类的原型上定义 toJSON() ActionScript 中的本机 JSON 实现镜像 ECMA-262 第 5 版中定义的 ECMAScript JSON 机制。由于 ECMAScript 不支持 类,因此 ActionScript 基于原型的调度定义 JSON 行为。原型是 ActionScript 3.0 类的前体,允许模拟继承以及成员添加和 重新定义。 ActionScript 允许您在任何类的原型上定义或重新定义 toJSON()。这种权限也适用于标记为 final 的类。在类原型上定义 toJSON() 时,您的定义将成为应用程序范围内该类的所有实例的最新定义。例如,下面介绍如何在 MovieClip 原型上定义 toJSON() 方法: MovieClip.prototype.toJSON = function(k):* { trace("prototype.toJSON() called."); return "toJSON"; } 当您的应用程序随后在任何 MovieClip 实例上调用 stringify() 时, stringify() 将返回 toJSON() 方法的输出: var mc:MovieClip = new MovieClip(); var js:String = JSON.stringify(mc); //"prototype toJSON() called." trace("js: " + js); //"js: toJSON" 您还可以在定义该方法的本地类中覆盖 toJSON()。例如,以下代码覆盖 Date.toJSON(): Date.prototype.toJSON = function (k):* { return "any date format you like via toJSON: "+ "this.time:"+this.time + " this.hours:"+this.hours; } var dt:Date = new Date(); trace(JSON.stringify(dt)); // "any date format you like via toJSON: this.time:1317244361947 this.hours:14" 102ACTIONSCRIPT 3.0 开发人员指南 使用本机 JSON 功能 上次更新 2014/12/1 定义或覆盖类级别的 toJSON() 并不总是需要应用程序使用原型重新定义 toJSON()。如果父类不是最终类,您也可以将 toJSON() 定义为子类的成员。例如, 您可以扩展 ByteArray 类并定义公用 toJSON() 函数: package { import flash.utils.ByteArray; public class MyByteArray extends ByteArray { public function MyByteArray() { } public function toJSON(s:String):* { return "MyByteArray"; } } } var ba:ByteArray = new ByteArray(); trace(JSON.stringify(ba)); //"ByteArray" var mba:MyByteArray = new MyByteArray(); //"MyByteArray" trace(JSON.stringify(mba)); //"MyByteArray" 如果类是动态类,您可以将 toJSON 属性添加到该类的对象中,并为其分配一个函数,如下所示: var d:Dictionary = new Dictionary(); trace(JSON.stringify((d))); // "Dictionary" d.toJSON = function(){return {c : "toJSON override."};} // overrides existing function trace(JSON.stringify((d))); // {"c":"toJSON override."} 您可以在任何 ActionScript 类上覆盖、定义或重新定义 toJSON()。但是,大多数内置 ActionScript 类不会定义 toJSON()。 Object 类不会以默认的原型定义 toJSON,也不会将其声明为类成员。只有其他少数本地类将该方法定义为原型函数。因此, 在大多数类中,您不能以传统方式覆盖 toJSON()。 不定义 toJSON 的本地类将通过内部 JSON 实施序列化为 JSON。请尽可能避免替换此内置功能。如果您定义 toJSON() 成员, 则 JSON 类将使用您的逻辑而不是其自己的函数。 使用 JSON.stringify() replacer 参数 如果需要在整个应用程序中更改类的 JSON 导出行为,则可以选择覆盖原型的 toJSON()。但是,在某些情况下,导出逻辑可能 只适用于瞬态条件下的特殊情况。要适应此小范围的更改,您可以使用 JSON.stringify() 方法的 replacer 参数。 stringify() 方法应用从 replacer 参数传递到要编码的对象的函数。此函数的签名与 toJSON() 的签名类似: function (k,v):* 与 toJSON() 不同, replacer 函数需要值 v 和密钥 k。此差异是必要的,因为 stringify() 是在静态 JSON 对象而不是要编码的对 象上定义的。当 JSON.stringify() 调用 replacer(k,v) 时,它将遍历原始输入对象。传递到 replacer 函数的隐式 this 参数表示保存 密钥和值的对象。由于 JSON.stringify() 不修改原始输入对象,因此该对象在要遍历的容器中保持不变。因此,您可以使用代码 this[k] 查询原始对象上的密钥。 v 参数保存 toJSON() 转换的值。 与 toJSON() 相同, replacer 函数可以返回任何类型的值。如果 replacer 返回字符串,则 JSON 引擎将对引号中的内容进行转 义,然后使用引号包装转义内容。此包装可确保 stringify() 接收到有效的 JSON 字符串对象,该对象在对 JSON.parse() 的后续 调用中仍然为一个字符串。 以下代码使用 replacer 参数和隐式 this 参数返回 Date 对象的 time 和 hours 值:103ACTIONSCRIPT 3.0 开发人员指南 使用本机 JSON 功能 上次更新 2014/12/1 JSON.stringify(d, function (k,v):* { return "any date format you like via replacer: "+ "holder[k].time:"+this[k].time + " holder[k].hours:"+this[k].hours; }); 使用 JSON.parse() reviver 参数 JSON.parse() 方法的 reviver 参数与 replacer 函数相反:它将 JSON 字符串转换为可使用的 ActionScript 对象。reviver 参数是 一个具有两个参数并返回任何类型的函数: function (k,v):* 在此函数中,k 是一个密钥,v 是 k 的值。与 stringify() 一样,parse() 遍历 JSON 密钥 - 值对,并将 reviver 函数 (如果存在) 应用于每个对。一个潜在的问题是:事实上,JSON 类不输出对象的 ActionScript 类名称。因此,了解要恢复的对象类型具有 一定的难度。如果是嵌套对象,此问题将特别麻烦。在设计 toJSON()、 replacer 和 reviver 函数时,您可以想办法在保持原对象 完整性的同时识别导出的 ActionScript 对象。 解析示例 下面的示例显示了恢复从 JSON 字符串解析的对象的策略。此示例定义 JSONGenericDictExample 和 JSONDictionaryExtnExample 两个类。JSONGenericDictExample 类是一个自定义 Dictionary 类。每个记录都包含一个 人的姓名、生日以及唯一 ID。每次调用 JSONGenericDictExample 构造函数时,均会将新创建的对象添加到内部静态数组, 并使用一个静态递增的整数作为其 ID。JSONGenericDictExample 类还定义了 revive() 方法,该方法只从较长的 id 成员提取 整数部分。 revive() 方法使用此整数来查找并返回正确的可恢复对象。 JSONDictionaryExtnExample 类扩展了 ActionScript Dictionary 类。其记录没有固定的结构,可以包含任何数据。在构 建 JSONDictionaryExtnExample 对象之后即为其指定数据,而不是作为类定义的属性来指定。 JSONDictionaryExtnExample 记录将 JSONGenericDictExample 对象用作密钥。JSONDictionaryExtnExample 对象恢 复时, JSONGenericDictExample.revive() 函数使用与 JSONDictionaryExtnExample 关联的 ID 来检索正确的密钥对象。 最重要的是, JSONDictionaryExtnExample.toJSON() 方法将返回包含 JSONDictionaryExtnExample 对象在内的标记字符 串。此字符串将 JSON 输出标识为属于 JSONDictionaryExtnExample 类。通过此标记,我们可以清楚地了解 JSON.parse() 期间处理的对象类型。 package { // Generic dictionary example: public class JSONGenericDictExample { static var revivableObjects = []; static var nextId = 10000; public var id; public var dname:String; public var birthday; public function JSONGenericDictExample(name, birthday) { revivableObjects[nextId] = this; this.id = "id_class_JSONGenericDictExample_" + nextId; this.dname = name; this.birthday = birthday; nextId++; } public function toString():String { return this.dname; } public static function revive(id:String):JSONGenericDictExample { var r:RegExp = /^id_class_JSONGenericDictExample_([0-9]*)$/; var res = r.exec(id); return JSONGenericDictExample.revivableObjects[res[1]]; } } } 104ACTIONSCRIPT 3.0 开发人员指南 使用本机 JSON 功能 上次更新 2014/12/1 package { import flash.utils.Dictionary; import flash.utils.ByteArray; // For this extension of dictionary, we serialize the contents of the // dictionary by using toJSON public final class JSONDictionaryExtnExample extends Dictionary { public function toJSON(k):* { var contents = {}; for (var a in this) { contents[a.id] = this[a]; } // We also wrap the contents in an object so that we can // identify it by looking for the marking property "class E" // while in the midst of JSON.parse. return {"class JSONDictionaryExtnExample": contents}; } // This is just here for debugging and for illustration public function toString():String { var retval = "[JSONDictionaryExtnExample <"; var printed_any = false; for (var k in this) { retval += k.toString() + "=" + "[e="+this[k].earnings + ",v="+this[k].violations + "], " printed_any = true; } if (printed_any) retval = retval.substring(0, retval.length-2); retval += ">]" return retval; } } } 下列运行时脚本调用 JSONDictionaryExtnExample 对象上的 JSON.parse() 时, reviver 函数将调用 JSONDictionaryExtnExample 中每个对象上的 JSONGenericDictExample revive()。此调用将提取表示对象密钥的 ID。 JSONGenericDictExample.revive() 函数使用此 ID 从私有静态数组中检索并返回存储的 JSONDictionaryExtnExample 对象。 import flash.display.MovieClip; import flash.text.TextField; var a_bob1:JSONGenericDictExample = new JSONGenericDictExample("Bob", new Date(Date.parse("01/02/1934"))); var a_bob2:JSONGenericDictExample = new JSONGenericDictExample("Bob", new Date(Date.parse("05/06/1978"))); var a_jen:JSONGenericDictExample = new JSONGenericDictExample("Jen", new Date(Date.parse("09/09/1999"))); var e = new JSONDictionaryExtnExample(); e[a_bob1] = {earnings: 40, violations: 2}; e[a_bob2] = {earnings: 10, violations: 1}; e[a_jen] = {earnings: 25, violations: 3}; trace("JSON.stringify(e): " + JSON.stringify(e)); // {"class JSONDictionaryExtnExample": //{"id_class_JSONGenericDictExample_10001": //{"earnings":10,"violations":1}, //"id_class_JSONGenericDictExample_10002": //{"earnings":25,"violations":3}, //"id_class_JSONGenericDictExample_10000": // {"earnings":40,"violations":2}}} var e_result = JSON.stringify(e); 105ACTIONSCRIPT 3.0 开发人员指南 使用本机 JSON 功能 上次更新 2014/12/1 var e1 = new JSONDictionaryExtnExample(); var e2 = new JSONDictionaryExtnExample(); // It's somewhat easy to convert the string from JSON.stringify(e) back // into a dictionary (turn it into an object via JSON.parse, then loop // over that object's properties to construct a fresh dictionary). // // The harder exercise is to handle situations where the dictionaries // themselves are nested in the object passed to JSON.stringify and // thus does not occur at the topmost level of the resulting string. // // (For example: consider roundtripping something like // var tricky_array = [e1, [[4, e2, 6]], {table:e3}] // where e1, e2, e3 are all dictionaries. Furthermore, consider // dictionaries that contain references to dictionaries.) // // This parsing (or at least some instances of it) can be done via // JSON.parse, but it's not necessarily trivial. Careful consideration // of how toJSON, replacer, and reviver can work together is // necessary. var e_roundtrip = JSON.parse(e_result, // This is a reviver that is focused on rebuilding JSONDictionaryExtnExample objects. function (k, v) { if ("class JSONDictionaryExtnExample" in v) { // special marker tag; //see JSONDictionaryExtnExample.toJSON(). var e = new JSONDictionaryExtnExample(); var contents = v["class JSONDictionaryExtnExample"]; for (var i in contents) { // Reviving JSONGenericDictExample objects from string // identifiers is also special; // see JSONGenericDictExample constructor and // JSONGenericDictExample's revive() method. e[JSONGenericDictExample.revive(i)] = contents[i]; } return e; } else { return v; } }); trace("// == Here is an extended Dictionary that has been round-tripped =="); trace("// == Note that we have revived Jen/Jan during the roundtrip. =="); trace("e: " + e); //[JSONDictionaryExtnExample ] trace("e_roundtrip: " + e_roundtrip); //[JSONDictionaryExtnExample ] trace("Is e_roundtrip a JSONDictionaryExtnExample? " + (e_roundtrip is JSONDictionaryExtnExample)); //true trace("Name change: Jen is now Jan"); a_jen.dname = "Jan" trace("e: " + e); //[JSONDictionaryExtnExample ] trace("e_roundtrip: " + e_roundtrip); //[JSONDictionaryExtnExample ] 106 上次更新 2014/12/1 第 8 章 : 处理事件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 利用事件处理系统,程序员可以十分方便地响应用户输入和系统事件。 ActionScript 3.0 事件模型不仅方便,而且符合标准, 并且它还与显示列表完美集成在一起。新的事件模型基于文档对象模型 (DOM) 第 3 级事件规范,是业界标准的事件处理体系 结构,为 ActionScript 程序员提供了强大而直观的事件处理工具。 ActionScript 3.0 事件处理系统与显示列表密切交互。 若要对显示列表有基本的了解,请阅读第 126 页的 “ 显示编程 ”。 更多帮助主题 flash.events 包 文档对象模型 (DOM) 第 3 级事件规范 事件处理基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 您可以将事件视为 SWF 文件中发生的程序员感兴趣的任何类型的事件。例如,大多数 SWF 文件都支持某些类型的用户交互, 无论是像响应鼠标单击这样简单的用户交互,还是像接受和处理表单中输入的数据这样复杂的用户交互。与 SWF 文件进行的 任何此类用户交互都可以视为事件。也可能会在没有任何直接用户交互的情况下发生事件,例如,从服务器加载完数据或者连 接的摄像头变为活动状态时。 在 ActionScript 3.0 中,每个事件都由一个事件对象表示。事件对象是 Event 类或其某个子类的实例。事件对象不但存储有关 特定事件的信息,还包含便于操作此事件对象的方法。例如,当 Flash Player 或 AIR 检测到鼠标单击时,它会创建一个事件对 象(MouseEvent 类的实例)以表示该特定鼠标单击事件。 创建事件对象之后,Flash Player 或 AIR 即 “ 调度 ” 该事件对象,这意味着将该事件对象传递给作为事件目标的对象。作为被 调度事件对象的目标的对象称为 “ 事件目标 ”。例如,当连接的摄像头变为活动状态时, Flash Player 会向事件目标直接调度 一个事件对象,此时,该事件对象就是代表摄像头的对象。但是,如果事件目标位于显示列表中,则事件对象会沿显示列表层 次向下传递,直到到达事件目标为止。在某些情况下,事件对象随后会沿着相同路线在显示列表层次中向上 “ 冒泡 ” 回去。这 种在显示列表层次中遍历的活动称为事件流。 您可以使用事件侦听器 “ 侦听 ” 代码中的事件对象。 “ 事件侦听器 ” 是您编写的用于响应特定事件的函数或方法。若要确保您 的程序响应事件,必须将事件侦听器添加到事件目标,或添加到作为事件对象事件流的一部分的任何显示列表对象。 无论何时编写事件侦听器代码,该代码都会采用以下基本结构 (以粗体显示的元素是占位符,您将针对具体情况对其进行填 写): function eventResponse(eventObject:EventType):void { // Actions performed in response to the event go here. } eventTarget.addEventListener(EventType.EVENT_NAME, eventResponse); 此代码完成两项任务。首先,它定义一个函数,这是指定为响应事件而执行的动作的方法。接下来,调用源对象的 addEventListener() 方法,实际上就是为指定事件 “ 订阅 ” 该函数,以便当该事件发生时,执行该函数的操作。当事件实际发生 时,事件目标将检查其注册为事件侦听器的所有函数和方法的列表。然后,它依次调用每个函数或方法,同时将事件对象作为 参数传递。107ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 您需要在此代码中更改四项内容以创建自己的事件侦听器。第一,必须将函数名称更改为要使用的名称 (必须在两个位置更改 此内容,代码将在此处显示 eventResponse)。第二,必须为要侦听的事件 (代码中的 EventType)所调度的事件对象指定相 应的类名称,并且必须为特定事件 (列表中的 EVENT_NAME)指定相应的常量。第三,必须针对调度事件 (此代码中的 eventTarget)的对象调用 addEventListener() 方法。您可以选择更改用作函数参数 (此代码中的 eventObject)的变量的名 称。 重要概念和术语 以下参考列表包括您在编写事件处理例程时会遇到的重要术语。 冒泡 一些事件会发生冒泡,以使父显示对象可以响应其子项调度的事件。 冒泡阶段 事件流中向上传播到父显示对象的事件所在部分。冒泡阶段发生在捕获和目标阶段之后。 捕获阶段 事件流中从最常规的目标向下传播到最具体的目标对象的事件所在部分。捕获阶段发生在目标和冒泡阶段之前。 默认行为 某些事件包含通常与事件同时发生的行为,称为默认行为。例如,当用户在文本字段中键入文本时,将引发文本输入 事件。该事件的默认行为是实际显示在文本字段中键入的字符,但您可以覆盖该默认行为 (如果由于某种原因,您不希望显示 键入的字符)。 调度 通知事件侦听器发生了某事件。 事件 在某对象上发生的情况,该对象可以将此情况告知其他对象。 事件流 当显示列表上的对象 (屏幕上显示的对象)发生事件时,将通知包括该对象在内的所有对象发生了此事件,并依次通 知它们的事件侦听器。此过程从舞台开始,并在显示列表中一直进行到发生事件的实际对象,然后再返回到舞台。此过程称为 事件流。 事件对象 一个包含发生的特定事件的相关信息的对象,当调度事件时,此信息将被发送到所有侦听器。 事件目标 实际调度事件的对象。例如,如果用户单击位于 Sprite (位于舞台内)内的按钮,则所有这些对象将调度事件,但 事件目标是指实际发生事件的对象,此处指单击的按钮。 侦听器 一个已将自身注册到某对象的对象或函数,以指示当特定事件发生时应该通知它。 目标阶段 事件已到达最具体的可能目标时所在的事件流点。目标阶段发生在捕获和冒泡阶段之间。 ActionScript 3.0 事件处理与早期版本事件处理的不同之处 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 中的事件处理与早期 ActionScript 版本中的事件处理之间的一个最显著的区别是:在 ActionScript 3.0 中, 只有一个事件处理系统,而在早期的 ActionScript 版本中,则有几个不同的事件处理系统。本部分先概述早期 ActionScript 版本中的事件处理的工作原理,然后讨论 ActionScript 3.0 中的事件处理的变化情况。 早期 ActionScript 版本中的事件处理 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 之前的 ActionScript 版本中提供许多不同的方法来处理事件: • on() 事件处理函数,可以直接放在 Button 和 MovieClip 实例上 • onClipEvent() 处理函数,可以直接放在 MovieClip 实例上 • 回调函数属性,例如 XML.onload 和 Camera.onActivity • 使用 addListener() 方法注册的事件侦听器108ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 • 部分实现了 DOM 事件模型的 UIEventDispatcher 类。 其中的每一种机制都有其自己的若干优点和局限性。on() 和 onClipEvent() 处理函数易于使用,但使随后对项目的维护变得较为 困难,因为很难查找直接放在按钮和影片剪辑上的代码。回调函数也很容易实现,但对于任何指定事件,仅限于使用一个回调 函数。事件侦听器较难实现:它们不但要求创建侦听器对象和函数,而且要求向生成事件的对象注册侦听器。这虽然增加了开 销,但您可以创建若干侦听器对象,并针对同一个事件注册这些对象。 对 ActionScript 2.0 组件的开发形成了另一个事件模型。该新模型包含在 UIEventDispatcher 类中,并且基于 DOM 事件规 范的子集。熟悉组件事件处理的开发人员将会发现过渡到新的 ActionScript 3.0 事件模型相对来说较为容易。 遗憾的是,各个事件模型使用的语法以不同的方式相互重叠,并且在其他方面各自不同。例如,在 ActionScript 2.0 中,某些 属性 (例如 TextField.onChanged)可用作回调函数或事件侦听器。但是,根据您是否在使用支持侦听器或六个类之一的 UIEventDispatcher 类,用于注册侦听器对象的语法有所不同。对于 Key、Mouse、MovieClipLoader、Selection、Stage 和 TextField 类;请使用 addListener() 方法,但对于组件事件处理,请使用名为 addEventListener() 的方法。 不同事件处理模型所导致的另一个复杂性是:根据所使用的机制的不同,事件处理函数的范围大不相同。也就是说,关键字 this 的含义在各个事件处理系统中并不一致。 ActionScript 3.0 中的事件处理 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 引入了单一事件处理模型,以替代以前各语言版本中存在的众多不同的事件处理机制。该新事件模型基于文 档对象模型 (DOM) 第 3 级事件规范。虽然 SWF 文件格式并不专门遵循文档对象模型标准,但显示列表和 DOM 结构之间存 在的相似性足以使 DOM 事件模型的实现成为可能。显示列表中的对象类似于 DOM 层次结构中的节点,在本讨论中,术语 “ 显示列表对象 ” 和 “ 节点 ” 可互换使用。 Flash Player 和 AIR 实现的 DOM 事件模型包括一个名为 “ 默认行为 ” 的概念。“ 默认行为 ” 是 Flash Player 或 AIR 作为特 定事件的正常后果而执行的操作。 默认行为 开发人员通常负责编写响应事件的代码。但在某些情况下,行为通常与某一事件关联,使得 Flash Player 或 AIR 会自动执行 该行为,除非开发人员添加了取消该行为的代码。由于 Flash Player 或 AIR 会自动表现该行为,因此这类行为称为默认行为。 例如,当用户在 TextField 对象中输入文本时,普遍期待文本显示在该 TextField 对象中,因此该行为被内置到 Flash Player 和 AIR 中。如果您不希望该默认行为发生,可以使用新的事件处理系统来取消它。当用户在 TextField 对象中输入文本时, Flash Player 或 AIR 会创建 TextEvent 类的实例以表示该用户输入。若要阻止 Flash Player 或 AIR 显示 TextField 对象中的 文本,必须访问该特定 TextEvent 实例并调用该实例的 preventDefault() 方法。 并非所有默认行为都可以被阻止。例如,当用户双击 TextField 对象中的单词时, Flash Player 和 AIR 会生成一个 MouseEvent 对象。无法阻止的默认行为是:加亮鼠标点击的单词。 许多类型的事件对象没有关联的默认行为。例如,当建立网络连接时, Flash Player 调度一个连接事件对象,但没有与该对象 关联的默认行为。Event 类及其子类的 API 文档列出了每一类型的事件,并说明所有关联的默认行为,以及是否可以阻止该行 为。 默认行为仅与由 Flash Player 或 AIR 所调度的事件对象关联,但通过 ActionScript 以编程方式调度的事件对象则不存在默认 行为。了解这一点很重要。例如,可以使用 EventDispatcher 类的方法来调度类型为 textInput 的事件对象,但该事件对象没 有关联的默认行为。也就是说, Flash Player 和 AIR 不会因为您以编程方式调度了 textInput 事件而在 TextField 对象中显示 字符。109ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 ActionScript 3.0 中事件侦听器的新增功能 对于使用 ActionScript 2.0 addListener() 方法的开发人员来说,了解 ActionScript 2.0 事件侦听器模型和 ActionScript 3.0 事 件模型之间的差别可能会有所帮助。下表说明两个事件模型之间的几个主要差别: • 若要在 ActionScript 2.0 中添加事件侦听器,请在某些情况下使用 addListener(),在其他情况下使用 addEventListener() ; 而在 ActionScript 3.0 中,则始终使用 addEventListener()。 • ActionScript 2.0 中没有事件流,这意味着,只能对广播事件的对象调用 addListener() 方法;而在 ActionScript 3.0 中, 可以对属于事件流一部分的任何对象调用 addEventListener() 方法。 • 在 ActionScript 2.0 中,事件侦听器可以是函数、方法或对象,而在 ActionScript 3.0 中,只有函数或方法可以是事件侦 听器。 事件流 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 只要发生事件,Flash Player 或 AIR 就会调度事件对象。如果事件目标不在显示列表中,则 Flash Player 或 AIR 将事件对象 直接调度到事件目标。例如,Flash Player 将 progress 事件对象直接调度到 URLStream 对象。但是,如果事件目标在显示列 表中,则 Flash Player 将事件对象调度到显示列表,事件对象将在显示列表中穿行,直到到达事件目标。 “ 事件流 ” 说明事件对象如何在显示列表中穿行。显示列表以一种可以用树结构来描述的层次形式进行组织。位于显示列表层 次顶部的是舞台,它是一个特殊的显示对象容器,用作显示列表的根。舞台由 flash.display.Stage 类表示,且只能通过显示对 象访问。每个显示对象都有一个名为 stage 的属性,该属性表示应用程序的舞台。 当 Flash Player 或 AIR 为显示列表相关的事件调度事件对象时,该事件对象将进行一次从舞台到 “ 目标节点 ” 的往返行程。 DOM 事件规范将目标节点定义为代表事件目标的节点。也就是说,目标节点是发生了事件的显示列表对象。例如,如果用户 单击名为 child1 的显示列表对象, Flash Player 或 AIR 将使用 child1 作为目标节点来调度事件对象。 从概念上来说,事件流分为三部分。第一部分称为捕获阶段,该阶段包括从舞台到目标节点的父节点范围内的所有节点。第二 部分称为目标阶段,该阶段仅包括目标节点。第三部分称为冒泡阶段。冒泡阶段包括从目标节点的父节点返回到舞台的行程中 遇到的节点。 如果将显示列表想像为一个垂直的层次,其中舞台位于顶层 (如下图显示),那么这些阶段的名称就更容易理解了: 舞台 父节点 Child1 节点 Child2 节点110ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 如果用户单击 Child1 Node,Flash Player 或 AIR 将向事件流调度一个事件对象。如下面的图像所示,对象的行程从舞台开始, 向下移到父节点,然后移到 Child1 节点,再 “ 冒泡 ” 返回到舞台 (即在行程中重新经过父节点,再返回到舞台)。 在此示例中,捕获阶段在首次向下行程中包括舞台和父节点。目标阶段包括在 Child1 花费的时间。冒泡阶段包括在向上返回到 根节点的行程中遇到的父节点和舞台。 事件流使现在的事件处理系统比 ActionScript 程序员以前使用的事件处理系统功能更为强大。早期版本的 ActionScript 中没 有事件流,这意味着事件侦听器只能添加到生成事件的对象。在 ActionScript 3.0 中,您不但可以将事件侦听器添加到目标节 点,还可以将它们添加到事件流中的任何节点。 当用户界面组件包含多个对象时,沿事件流添加事件侦听器的功能十分有用。例如,按钮对象通常包含一个用作按钮标签的文 本对象。如果无法将侦听器添加到事件流,您将必须将侦听器添加到按钮对象和文本对象,以确保您收到有关在按钮上任何位 置发生的单击事件的通知。而事件流的存在则使您可以将一个事件侦听器放在按钮对象上,以处理文本对象上发生的单击事件 或按钮对象上未被文本对象遮住的区域上发生的单击事件。 不过,并非每个事件对象都参与事件流的所有三个阶段。某些类型的事件 (例如 enterFrame 和 init 类型的事件)会直接调度到 目标节点,并不参与捕获阶段和冒泡阶段。其他事件可能以不在显示列表中的对象为目标,例如调度到 Socket 类的实例的事 件。这些事件对象也将直接流至目标对象,而不参与捕获和冒泡阶段。 要查明特定事件类型的行为,可以查看 API 文档或检查事件对象的属性。下面的部分介绍了如何检查事件对象的属性。 事件对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在新的事件处理系统中,事件对象有两个主要用途。首先,事件对象通过将特定事件的有关信息存储在一组属性中来表示实际 事件。其次,事件对象包含一组方法,可用于操作事件对象和影响事件处理系统的行为。 为方便对这些属性和方法的访问,Flash Player API 定义了一个 Event 类,作为所有事件对象的基类。Event 类定义所有事件 对象共有的一组基本属性和方法。 本部分首先讨论 Event 类属性,然后介绍 Event 类方法,最后说明 Event 类的子类存在的意义。 了解 Event 类的属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Event 类定义许多只读属性和常量,以提供有关事件对象的重要信息。以下内容尤其重要: • 事件对象类型由常量表示,并存储在 Event.type 属性中。 • 事件的默认行为是否可以被阻止由布尔值表示,并存储在 Event.cancelable 属性中。 舞台 父节点 Child1 节点 Child2 节点 捕获 阶段 冒泡 阶段 目标阶段111ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 • 事件流信息包含在其余属性中。 事件对象类型 每个事件对象都有关联的事件类型。数据类型以字符串值的形式存储在 Event.type 属性中。知道事件对象的类型是非常有用 的,这样您的代码就可以区分不同类型的对象。例如,下面的代码指定 clickHandler() 侦听器函数应响应传递给 myDisplayObject 的任何鼠标单击事件对象。 myDisplayObject.addEventListener(MouseEvent.CLICK, clickHandler); 大约有 20 多种事件类型与 Event 类自身关联并由 Event 类常量表示,其中某些数据类型显示在摘自 Event 类定义的以下代码 中: package flash.events { public class Event { // class constants public static const ACTIVATE:String = "activate"; public static const ADDED:String= "added"; // remaining constants omitted for brevity } } 这些常量提供了引用特定事件类型的简便方法。您应使用这些常量而不是它们所代表的字符串。如果您的代码中拼错了某个常 量名称,编译器将捕获到该错误,但如果您改为使用字符串,则编译时可能不会出现拼写错误,这可能导致难以调试的意外行 为。例如,添加事件侦听器时,使用以下代码: myDisplayObject.addEventListener(MouseEvent.CLICK, clickHandler); 而不是使用: myDisplayObject.addEventListener("click", clickHandler); 默认行为信息 代码可通过访问 cancelable 属性来检查是否可以阻止任何给定事件对象的默认行为。cancelable 属性包含一个布尔值,用于指示 是否可以阻止默认行为。您可以使用 preventDefault() 方法阻止或取消与少量事件关联的默认行为。有关详细信息,请参阅 第 112 页的 “ 了解 Event 类的方法 ” 下的 “ 取消默认事件行为 ”。 事件流信息 其余 Event 类属性包含有关事件对象及其与事件流的关系的重要信息,如以下列表所述: • bubbles 属性包含有关事件流中事件对象参与的部分的信息。 • eventPhase 属性指示事件流中的当前阶段。 • target 属性存储对事件目标的引用。 • currentTarget 属性存储对当前正在处理事件对象的显示列表对象的引用。 bubbles 属性 如果事件对象参与事件流的冒泡阶段,则将该事件称为 “ 冒泡 ”,这指的是从目标节点将事件对象往回传递,经过目标节点的 父节点,直到到达舞台。 Event.bubbles 属性存储一个布尔值,用于指示事件对象是否参与冒泡阶段。由于冒泡的所有事件还参 与捕获和目标阶段,因此这些事件参与事件流的所有三个阶段。如果值为 true,则事件对象参与所有三个阶段。如果值为 false,则事件对象不参与冒泡阶段。112ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 eventPhase 属性 您可以通过调查任何事件对象的 eventPhase 属性来确定事件阶段。 eventPhase 属性包含一个无符号整数值,该值代表三个事件 流阶段中的一个阶段。 Flash Player API 定义了单独的 EventPhase 类,该类包含三个对应于三个无符号整数值的常量,如以 下摘录代码中所示: package flash.events { public final class EventPhase { public static const CAPTURING_PHASE:uint = 1; public static const AT_TARGET:uint = 2; public static const BUBBLING_PHASE:uint= 3; } } 这些常量对应于 eventPhase 属性的三个有效值。使用这些常量可以使您的代码可读性更好。例如,如果要确保仅当事件目标在 目标阶段中时才调用名为 myFunc() 的函数,您可以使用以下代码来测试此条件: if (event.eventPhase == EventPhase.AT_TARGET) { myFunc(); } target 属性 target 属性包含对作为事件目标的对象的引用。在某些情况下,这很简单,例如当麦克风变为活动状态时,事件对象的目标是 Microphone 对象。但是,如果目标在显示列表中,就必须考虑显示列表层次。例如,如果用户在包括重叠的显示列表对象的 某一点输入一个鼠标单击,则 Flash Player 和 AIR 始终会选择距离舞台层次最深的对象作为事件目标。 对于复杂的 SWF 文件,特别是那些通常使用更小的子对象来修饰按钮的 SWF 文件,target 属性可能并不常用,因为它通常指 向按钮的子对象,而不是按钮。在这些情况下,常见的做法是将事件侦听器添加到按钮并使用 currentTarget 属性,因为该属性 指向按钮,而 target 属性可能指向按钮的子对象。 currentTarget 属性 currentTarget 属性包含对当前正在处理事件对象的对象的引用。您并不知道哪个节点当前正在处理您要检查的事件对象,虽然 这似乎很奇怪,但请记住,您可以向该事件对象的事件流中的任何显示对象添加侦听器函数,并且可以将侦听器函数放在任何 位置。而且,可以将相同的侦听器函数添加到不同的显示对象。随着项目大小和复杂性的增加, currentTarget 属性会变得越来 越有用。 了解 Event 类的方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 有三种类别的 Event 类方法: • 实用程序方法:可以创建事件对象的副本或将其转换为字符串 • 事件流方法:用于从事件流中删除事件对象 • 默认行为方法:可阻止默认行为或检查是否已阻止默认行为 Event 类实用程序方法 Event 类中有两个实用程序方法。clone() 方法用于创建事件对象的副本。toString() 方法用于生成事件对象属性的字符串表示形 式以及它们的值。这两个方法都由事件模型系统在内部使用,但对开发人员公开以用于一般用途。 对于创建 Event 类的子类的高级开发人员来说,必须覆盖和实现两个实用程序方法的版本,以确保事件子类正常使用。113ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 停止事件流 可以调用 Event.stopPropagation() 方法或 Event.stopImmediatePropagation() 方法来阻止在事件流中继续执行事件对象。这两种 方法几乎相同,唯一的不同之处在于是否允许执行当前节点的其他事件侦听器: • Event.stopPropagation() 方法可阻止事件对象移到下一个节点,但只有在允许执行当前节点上的任何其他事件侦听器之后才 起作用。 • Event.stopImmediatePropagation() 方法也可阻止事件对象移到下一个节点,但不允许执行当前节点上的任何其他事件侦听 器。 调用其中任何一个方法对是否发生与事件关联的默认行为没有影响。使用 Event 类的默认行为方法可以阻止默认行为。 取消事件默认行为 与取消默认行为有关的两个方法是 preventDefault() 方法和 isDefaultPrevented() 方法。调用 preventDefault() 方法可取消与事件 关联的默认行为。若要查看是否已针对事件对象调用了 preventDefault(),请调用 isDefaultPrevented() 方法;如果已经调用,该 方法将返回值 true,否则返回值 false。 preventDefault() 方法仅在可以取消事件的默认行为时才起作用。可通过参考该事件类型的 API 文档或使用 ActionScript 检查 事件对象的 cancelable 属性来确定是否属于这种情况。 取消默认行为对事件对象通过事件流的进度没有影响。使用 Event 类的事件流方法可以从事件流中删除事件对象。 Event 类的子类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 对于很多事件, Event 类中定义的一组公共属性已经足够了。但是, Event 类中可用的属性无法捕获其他事件具有的独特的特 性。 ActionScript 3.0 为这些事件定义了 Event 类的几个子类。 每个子类提供了对该类别的事件唯一的附加属性和事件类型。例如,与鼠标输入相关的事件具有若干独特的特性,无法被 Event 类中定义的属性捕获。MouseEvent 类添加了 10 个属性,扩展了 Event 类。这 10 个属性包含诸如鼠标事件的位置和在 鼠标事件过程中是否按下了特定键等信息。 Event 子类还包含代表与子类关联的事件类型的常量。例如, MouseEvent 类定义几种鼠标事件类型的内容,包括 click、 doubleClick、 mouseDown 和 mouseUp 事件类型。 正如第 110 页的 “ 事件对象 ” 下的 “Event 类实用程序方法 ” 一节所述,创建 Event 子类时,必须覆盖 clone() 和 toString() 方 法以实现特定于该子类的功能。 事件侦听器 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 事件侦听器也称为事件处理函数,是 Flash Player 和 AIR 为响应特定事件而执行的函数。添加事件侦听器的过程分为两步。 首先,为 Flash Player 或 AIR 创建一个为响应事件而执行的函数或类方法。这有时称为侦听器函数或事件处理函数。然后,使 用 addEventListener() 方法,在事件的目标或位于适当事件流上的任何显示列表对象中注册侦听器函数。 114ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 创建侦听器函数 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 创建侦听器函数是 ActionScript 3.0 事件模型与 DOM 事件模型不同的一个方面。在 DOM 事件模型中,事件侦听器和侦听 器函数之间有一个明显的不同:即事件侦听器是实现 EventListener 接口的类的实例,而侦听器是该类的名为 handleEvent() 的 方法。在 DOM 事件模型中,您注册的是包含侦听器函数的类实例,而不是实际的侦听器函数。 在 ActionScript 3.0 事件模型中,事件侦听器和侦听器函数之间没有区别。ActionScript 3.0 没有 EventListener 接口,侦听 器函数可以在类外部定义,也可以定义为类的一部分。此外,无需将侦听器函数命名为 handleEvent() — 可以将它们命名为任 何有效的标识符。在 ActionScript 3.0 中,您注册的是实际侦听器函数的名称。 在类外部定义的侦听器函数 以下代码创建一个显示红色正方形的简单 SWF 文件。名为 clickHandler() 的侦听器函数 (不是类的一部分)侦听红色正方形 上的鼠标单击事件。 package { import flash.display.Sprite; public class ClickExample extends Sprite { public function ClickExample() { var child:ChildSprite = new ChildSprite(); addChild(child); } } } import flash.display.Sprite; import flash.events.MouseEvent; class ChildSprite extends Sprite { public function ChildSprite() { graphics.beginFill(0xFF0000); graphics.drawRect(0,0,100,100); graphics.endFill(); addEventListener(MouseEvent.CLICK, clickHandler); } } function clickHandler(event:MouseEvent):void { trace("clickHandler detected an event of type: " + event.type); trace("the this keyword refers to: " + this); } 当用户通过单击正方形与生成的 SWF 文件交互时, Flash Player 或 AIR 生成以下跟踪输出: clickHandler detected an event of type: click the this keyword refers to: [object global] 请注意,事件对象作为参数传递到 clickHandler()。这就允许您的侦听器函数检查事件对象。在该示例中,使用事件对象的 type 属性来确定该事件是否为单击事件。 该示例还检查 this 关键字的值。在本例中, this 表示全局对象,这是因为函数是在任何自定义类或对象外部定义的。115ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 定义为类方法的侦听器函数 下面的示例与前面定义 ClickExample 类的示例相同,只是将 clickHandler() 函数定义为 ChildSprite 类的方法: package { import flash.display.Sprite; public class ClickExample extends Sprite { public function ClickExample() { var child:ChildSprite = new ChildSprite(); addChild(child); } } } import flash.display.Sprite; import flash.events.MouseEvent; class ChildSprite extends Sprite { public function ChildSprite() { graphics.beginFill(0xFF0000); graphics.drawRect(0,0,100,100); graphics.endFill(); addEventListener(MouseEvent.CLICK, clickHandler); } private function clickHandler(event:MouseEvent):void { trace("clickHandler detected an event of type: " + event.type); trace("the this keyword refers to: " + this); } } 当用户通过单击红色正方形与生成的 SWF 文件交互时, Flash Player 或 AIR 生成以下跟踪输出: clickHandler detected an event of type: click the this keyword refers to: [object ChildSprite] 请注意, this 关键字引用名为 child 的 ChildSprite 实例。这是与 ActionScript 2.0 相比行为方面的一个变化。如果您使用过 ActionScript 2.0 中的组件,您可能会记得,将类方法传递给 UIEventDispatcher.addEventListener() 时,方法的作用域被绑定 到广播事件的组件,而不是在其中定义侦听器方法的类。也就是说,如果在 ActionScript 2.0 中使用该技术, this 关键字将引 用广播事件的组件,而不是 ChildSprite 实例。 这对于某些程序员来说是一个重要问题,因为这意味着他们无法访问包含侦听器方法的类的其他方法和属性。过去, ActionScript 2.0 程序员可以使用 mx.util.Delegate 类更改侦听器方法的作用域以解决该问题。不过,现在已不再需要这样做 了,因为 ActionScript 3.0 在调用 addEventListener() 时会创建一个绑定方法。这样, this 关键字引用名为 child 的 ChildSprite 实例,且程序员可以访问 ChildSprite 类的其他方法和属性。 不应使用的事件侦听器 还有第三种技术可用于创建一个通用对象,该对象具有指向动态分配的侦听器函数的属性,但不推荐使用该技术。在此讨论这 种技术是因为它在 ActionScript 2.0 中经常使用,但在 ActionScript 3.0 中不应使用。建议不要使用此项技术,因为 this 关键 字将引用全局对象,而不引用您的侦听器对象。 下面的示例与前面的 ClickExample 类示例相同,只是将侦听器函数定义为名为 myListenerObj 的通用对象的一部分:116ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 package { import flash.display.Sprite; public class ClickExample extends Sprite { public function ClickExample() { var child:ChildSprite = new ChildSprite(); addChild(child); } } } import flash.display.Sprite; import flash.events.MouseEvent; class ChildSprite extends Sprite { public function ChildSprite() { graphics.beginFill(0xFF0000); graphics.drawRect(0,0,100,100); graphics.endFill(); addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler); } } var myListenerObj:Object = new Object(); myListenerObj.clickHandler = function (event:MouseEvent):void { trace("clickHandler detected an event of type: " + event.type); trace("the this keyword refers to: " + this); } 跟踪的结果将类似如下: clickHandler detected an event of type: click the this keyword refers to: [object global] 您可能以为 this 引用 myListenerObj,且跟踪输出应为 [object Object],但实际上它引用的是全局对象。将动态属性名称作为参 数传递给 addEventListener() 时,Flash Player 或 AIR 无法创建绑定方法。这是因为作为 listener 参数传递的只不过是侦听器函 数的内存地址, Flash Player 和 AIR 无法将该内存地址与 myListenerObj 实例关联起来。 管理事件侦听器 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用 IEventDispatcher 接口的方法来管理侦听器函数。IEventDispatcher 接口是 ActionScript 3.0 版本的 DOM 事件模型 的 EventTarget 接口。虽然名称 IEventDispatcher 似乎暗示着其主要用途是发送 (调度)事件对象,但该类的方法实际上更 多用于注册、检查和删除事件侦听器。 IEventDispatcher 接口定义五个方法,如以下代码中所示:117ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 package flash.events { public interface IEventDispatcher { function addEventListener(eventName:String, listener:Object, useCapture:Boolean=false, priority:Integer=0, useWeakReference:Boolean=false):Boolean; function removeEventListener(eventName:String, listener:Object, useCapture:Boolean=false):Boolean; function dispatchEvent(eventObject:Event):Boolean; function hasEventListener(eventName:String):Boolean; function willTrigger(eventName:String):Boolean; } } Flash Player API 使用 EventDispatcher 类来实现 IEventDispatcher 接口,该类用作可以是事件目标或事件流一部分的所有 类的基类。例如, DisplayObject 类继承自 EventDispatcher 类。这意味着,显示列表中的所有对象都可以访问 IEventDispatcher 接口的方法。 添加事件侦听器 addEventListener() 方法是 IEventDispatcher 接口的主要函数。使用它来注册侦听器函数。两个必需的参数是 type 和 listener。 type 参数用于指定事件的类型。 listener 参数用于指定发生事件时将执行的侦听器函数。 listener 参数可以是对函数或类方法的 引用。 指定 listener 参数时,不要使用括号。例如,在下面的 addEventListener() 方法调用中,指定 clickHandler() 函数时没有使用括 号: addEventListener(MouseEvent.CLICK, clickHandler) 通过使用 addEventListener() 方法的 useCapture 参数,可以控制侦听器将处于活动状态的事件流阶段。如果 useCapture 设置为 true,侦听器将在事件流的捕获阶段成为活动状态。如果 useCapture 设置为 false,侦听器将在事件流的目标阶段和冒泡阶段处 于活动状态。若要在事件流的所有阶段侦听某一事件,您必须调用 addEventListener() 两次,第一次调用时将 useCapture 设置 为 true,第二次调用时将 useCapture 设置为 false。 addEventListener() 方法的 priority 参数并不是 DOM Level 3 事件模型的正式部分。 ActionScript 3.0 中包括它是为了在组织 事件侦听器时提供更大的灵活性。调用 addEventListener() 时,可以将一个整数值作为 priority 参数传递,以设置该事件侦听器 的优先级。默认值为 0,但您可以将它设置为负整数值或正整数值。将优先执行此数字较大的事件侦听器。对于具有相同优先 级的事件侦听器,则按它们的添加顺序执行,因此将优先执行较早添加的侦听器。 可以使用 useWeakReference 参数来指定对侦听器函数的引用是弱引用还是正常引用。通过将此参数设置为 true,可避免侦听器 函数在不再需要时仍然存在于内存中的情况。Flash Player 和 AIR 使用一项称为 “ 垃圾回收 ” 的技术从内存中清除不再使用的 对象。如果不存在对某个对象的引用,则该对象被视为不再使用。垃圾回收器不考虑弱引用,这意味着如果侦听器函数仅具有 指向它的弱引用,则符合垃圾回收条件。 删除事件侦听器 可以使用 removeEventListener() 方法删除不再需要的事件侦听器。建议删除将不再使用的所有侦听器。必需的参数包括 eventName 和 listener 参数,这些参数与 addEventListener() 方法的必需参数相同。回想一下,您可以通过调用 addEventListener() 两次 (第一次调用时将 useCapture 设置为 true,第二次调用时将其设置为 false),在所有事件阶段侦听事 件。若要删除这两个事件侦听器,您需要调用 removeEventListener() 两次,第一次调用时将 useCapture 设置为 true,第二次调 用时将其设置为 false。118ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 调度事件 高级程序员可以使用 dispatchEvent() 方法将自定义事件对象调度到事件流。该方法唯一接受的参数是对事件对象的引用,此事 件对象必须是 Event 类的实例或子类。调度后,事件对象的 target 属性将设置为对其调用了 dispatchEvent() 的对象。 检查有无现有的事件侦听器 IEventDispatcher 接口的最后两个方法提供有关是否存在事件侦听器的有用信息。如果在特定显示列表对象上发现特定事件 类型的事件侦听器, hasEventListener() 方法将返回 true。如果发现特定显示列表对象的侦听器, willTrigger() 方法也会返回 true。但 willTrigger() 不但检查该显示对象上的侦听器,还会检查该显示列表对象在事件流所有阶段中的所有始祖上的侦听器。 没有侦听器的错误事件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 中处理错误的主要机制是异常而不是事件,但对于异步操作 (例如加载文件),异常处理不起作用。如果在 这样的异步操作中发生错误,Flash Player 和 AIR 会调度一个错误事件对象。如果不为错误事件创建侦听器,Flash Player 和 AIR 的调试器版本将打开一个对话框,其中包含有关该错误的信息。例如,调试版的 Flash Player 会在应用程序试图从无效 URL 加载文件时生成以下对话框来描述错误: 大多数错误事件基于 ErrorEvent 类,而且同样具有一个名为 text 的属性,它用于存储 Flash Player 或 AIR 显示的错误消息。 两个异常是 StatusEvent 和 NetStatusEvent 类。这两个类都具有一个 level 属性 (StatusEvent.level 和 NetStatusEvent.info.level)。当 level 属性的值为 "error" 时,这些事件类型被视为错误事件。 错误事件将不会导致 SWF 文件停止运行。它仅在浏览器插件和独立播放器的调试器版本上显示为对话框,在创作播放器的输 出面板中显示为消息,在 Adobe Flash Builder 的日志文件中显示为条目。在 Flash Player 或 AIR 的发行版中根本不会显示。 事件处理示例:闹钟 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Alarm Clock 示例包含一个时钟,供用户指定闹铃响起的时间,还包含一个在该时间显示的消息。Alarm Clock 示例是在第 1 页的 “ 使用日期和时间 ” 中的 SimpleClock 应用程序的基础上构建的。Alarm Clock 说明了在 ActionScript 3.0 中使用事件 的几个方面,其中包括: • 侦听和响应事件 • 向侦听器通知事件 • 创建自定义事件类型119ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 若要获取此范例的 Flash Professional 应用程序文件,请参阅 http://www.adobe.com/go/learn_programmingAS3samples_flash_cn。若要获取此范例的 Flex 应用程序文件,请参阅 http://www.adobe.com/go/as3examples_cn。可以在 Samples/AlarmClock 文件夹中找到 Alarm Clock 应用程序文件。 该应用程序包括以下文件: Alarm Clock 概述 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在此示例中,时钟的主要功能 (包括跟踪时间和显示时钟形状)重复使用 SimpleClock 应用程序代码,相关介绍请参阅第 5 页的 “ 日期和时间示例:简单模拟时钟 ”。 AlarmClock 类添加了闹钟所需的功能 (包括设置闹铃时间和在闹铃 “ 响起 ” 时显 示通知),从而扩展了该示例中的 SimpleClock 类。 在发生事情时提供通知,是创建事件的目的。 AlarmClock 类公开 Alarm 事件,其他对象可侦听该事件以执行所需操作。此 外,AlarmClock 类使用 Timer 类的实例来确定何时触发闹铃。和 AlarmClock 类一样,Timer 类提供一个事件,用于在经 过特定时间时通知其他对象(在本例中为 AlarmClock 实例)。就像大多数 ActionScript 应用程序一样,事件构成了 Alarm Clock 范例应用程序功能的重要部分。 触发闹铃 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如前所述, AlarmClock 类实际提供的唯一功能与设置和触发闹铃有关。内置的 Timer 类 (flash.utils.Timer) 为开发人员提 供了定义要在指定时间之后执行的代码的方法。 AlarmClock 类使用 Timer 实例来确定何时触发闹铃。 文件 说明 AlarmClockApp.mxml 或 AlarmClockApp.fla Flash 或 Flex 中的主应用程序文件 (分别为 FLA 和 MXML)。 com/example/programmingas3/clock/AlarmClock.as 一个扩展 SimpleClock 类的类,添加了闹钟功能。 com/example/programmingas3/clock/AlarmEvent.as 自定义事件类 (flash.events.Event 的子类),用作 AlarmClock 类的 alarm 事件的事件对象。 com/example/programmingas3/clock/AnalogClockFace.as 绘制一个圆的时钟形状以及基于时间的时针、分针和秒针 (如 SimpleClock 示例中所述)。 com/example/programmingas3/clock/SimpleClock.as 具有简单走时功能的时钟界面组件 (如 SimpleClock 示例中所述)。120ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 import flash.events.TimerEvent; import flash.utils.Timer; /** * The Timer that will be used for the alarm. */ public var alarmTimer:Timer; ... /** * Instantiates a new AlarmClock of a given size. */ public override function initClock(faceSize:Number = 200):void { super.initClock(faceSize); alarmTimer = new Timer(0, 1); alarmTimer.addEventListener(TimerEvent.TIMER, onAlarm); } AlarmClock 类中定义的 Timer 实例被命名为 alarmTimer。 initClock() 方法执行 AlarmClock 实例的所需设置操作,使用 alarmTimer 变量执行两个任务。首先,使用指示 Timer 实例等待 0 毫秒且仅触发其 timer 事件一次的参数实例化变量。实例 化 alarmTimer 后,代码调用变量的 addEventListener() 方法,指示它要监听该变量的 timer 事件。 Timer 实例的工作方式是: 在经过指定时间后调度其 timer 事件。 AlarmClock 类需要了解何时调度 timer 事件,以便触发自己的闹铃。通过调用 addEventListener(), AlarmClock 代码将自身作为侦听器在 alarmTimer 中进行注册。两个参数指示 AlarmClock 类要侦听 timer 事件 (由常量 TimerEvent.TIMER 指示),并且当事件发生时,应调用 AlarmClock 类的 onAlarm() 方法以响应事件。 为了实际设置闹铃,代码调用了 AlarmClock 类的 setAlarm() 方法,如下所示: /** * Sets the time at which the alarm should go off. * @param hour The hour portion of the alarm time. * @param minutes The minutes portion of the alarm time. * @param message The message to display when the alarm goes off. * @return The time at which the alarm will go off. */ public function setAlarm(hour:Number = 0, minutes:Number = 0, message:String = "Alarm!"):Date { this.alarmMessage = message; var now:Date = new Date(); // Create this time on today's date. alarmTime = new Date(now.fullYear, now.month, now.date, hour, minutes); // Determine if the specified time has already passed today. if (alarmTime <= now) { alarmTime.setTime(alarmTime.time + MILLISECONDS_PER_DAY); } // Stop the alarm timer if it's currently set. alarmTimer.reset(); // Calculate how many milliseconds should pass before the alarm should // go off (the difference between the alarm time and now) and set that // value as the delay for the alarm timer. alarmTimer.delay = Math.max(1000, alarmTime.time - now.time); alarmTimer.start(); return alarmTime; }121ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 此方法执行了几项操作,包括存储闹铃消息和创建一个 Date 对象 (alarmTime),该对象表示触发闹铃的实际时间。在该方法的 最后几行中,与当前讨论最相关的操作是设置和激活了 alarmTimer 变量的计时器。首先,调用其 reset() 方法,如果计时器已 运行,则将其停止并进行重置。接下来,从 alarmTime 变量值中减去当前时间 (由 now 变量表示),以确定需要经过多少毫秒 后才会触发闹铃。Timer 类并不会在某个绝对时间触发其 timer 事件,因此,分配给 alarmTimer 的 delay 属性的是该相对时间 差。最后,调用 start() 方法以实际启动计时器。 一旦经过指定时间,alarmTimer 将调度 timer 事件。由于 AlarmClock 类已将其 onAlarm() 方法注册为该事件的侦听器,因此 发生 timer 事件时,将调用 onAlarm()。 /** * Called when the timer event is dispatched. */ public function onAlarm(event:TimerEvent):void { trace("Alarm!"); var alarm:AlarmEvent = new AlarmEvent(this.alarmMessage); this.dispatchEvent(alarm); } 注册为事件侦听器的方法必须使用适当的签名 (即,方法的参数集和返回类型)来定义。若要侦听 Timer 类的 timer 事件,方 法必须定义一个数据类型为 TimerEvent (flash.events.TimerEvent) 的参数,该参数是 Event 类的子类。当 Timer 实例调用 其事件侦听器时,会传递一个 TimerEvent 实例作为事件对象。 向其他代码通知闹铃 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 和 Timer 类一样, AlarmClock 类提供了一个事件,以允许其他代码在闹铃响起时收到通知。对于类而言,要使用内置于 ActionScript 中的事件处理框架,必须实现 flash.events.IEventDispatcher 接口。通常,这是通过扩展 flash.events.EventDispatcher 类(提供 IEventDispatcher 的标准实现)或 EventDispatcher 的某个子类来完成的。如前所 述,AlarmClock 类扩展了 SimpleClock 类,SimpleClock 类(通过继承链)扩展了 EventDispatcher 类。 所有这些意味着 AlarmClock 类已经具有内置功能以提供自己的事件。 其他代码可通过调用 AlarmClock 从 EventDispatcher 继承的 addEventListener() 方法进行注册,以获得 AlarmClock 类的 alarm 事件的通知。当 AlarmClock 实例准备通知其他代码已引发其 alarm 事件时,它会调用 dispatchEvent() 方法进行通知, 该方法同样是从 EventDispatcher 继承的。 var alarm:AlarmEvent = new AlarmEvent(this.alarmMessage); this.dispatchEvent(alarm); 这些代码行摘自 AlarmClock 类的 onAlarm() 方法 (前面完整介绍过)。调用 AlarmClock 实例的 dispatchEvent() 方法,该 方法接下来通知所有注册的侦听器:已触发 AlarmClock 实例的 alarm 事件。传递给 dispatchEvent() 的参数是要一直传递到侦 听器方法的事件对象。在本例中,它是 AlarmEvent 类的实例,即为本示例专门创建的 Event 子类。 提供自定义 Alarm 事件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 所有事件侦听器都接收一个事件对象参数,该参数提供有关要触发的特定事件的信息。在许多情况下,事件对象是 Event 类的 实例。但在某些情况下,向事件侦听器提供其他信息很有用。实现该目的的一个常用方法是定义一个新类 (Event 类的子 类),并将该类的实例用作事件对象。在本示例中,当调度 AlarmClock 类的 alarm 事件时,会将一个 AlarmEvent 实例用作 事件对象。在此介绍的 AlarmEvent 类提供有关 alarm 事件的其他信息,具体来说是闹铃消息:122ACTIONSCRIPT 3.0 开发人员指南 处理事件 上次更新 2014/12/1 import flash.events.Event; /** * This custom Event class adds a message property to a basic Event. */ public class AlarmEvent extends Event { /** * The name of the new AlarmEvent type. */ public static const ALARM:String = "alarm"; /** * A text message that can be passed to an event handler * with this event object. */ public var message:String; /** *Constructor. *@param message The text to display when the alarm goes off. */ public function AlarmEvent(message:String = "ALARM!") { super(ALARM); this.message = message; } ... } 要创建自定义事件对象类,最好的方法是定义一个扩展 Event 类的类,如前面的示例中所示。为了补充继承的功能, AlarmEvent 类定义一个属性 message,该属性包含与事件关联的闹铃消息的文本; message 是作为 AlarmEvent 构造函数中 的参数传入的。 AlarmEvent 类还定义常量 ALARM,当调用 AlarmClock 类的 addEventListener() 方法时,该常量可用于引 用特定事件 (alarm)。 除了添加自定义功能外,作为 ActionScript 事件处理框架的一部分,每个 Event 子类还必须覆盖继承的 clone() 方法。Event 子类还可以选择性地覆盖继承的 toString() 方法,以便在调用 toString() 方法时返回的值中包括自定义事件的属性。 /** * Creates and returns a copy of the current instance. * @return A copy of the current instance. */ public override function clone():Event { return new AlarmEvent(message); } /** * Returns a String containing all the properties of the current * instance. * @return A string representation of the current instance. */ public override function toString():String { return formatToString("AlarmEvent", "type", "bubbles", "cancelable", "eventPhase", "message"); } 被覆盖的 clone() 方法需要返回自定义 Event 子类的新实例,并且设置了所有自定义属性以匹配当前实例。在被覆盖的 toString() 方法中,实用程序方法 formatToString() (从 Event 继承)用于提供一个字符串,包括自定义类型的名称以及所有属 性的名称和值。123 上次更新 2014/12/1 第 9 章 : 使用应用程序域 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ApplicationDomain 类的用途是存储 ActionScript 3.0 定义表。 SWF 文件中的所有代码被定义为存在于应用程序域中。可 以使用应用程序域划分位于同一个安全域中的类。这允许同一个类存在多个定义,并且还允许子级重用父级定义。 在使用 Loader 类 API 加载用 ActionScript 3.0 编写的外部 SWF 文件时,可以使用应用程序域。(请注意,在加载图像或用 ActionScript 1.0 或 ActionScript 2.0 编写的 SWF 文件时不能使用应用程序域。)包含在已加载类中的所有 ActionScript 3.0 定义都存储在应用程序域中。加载 SWF 文件时,通过将 LoaderContext 对象的 applicationDomain 参数设置为 ApplicationDomain.currentDomain,可以指定文件包含在 Loader 对象所在的相同应用程序域中。通过将加载的 SWF 文件放 在同一个应用程序域中,可以直接访问它的类。如果加载的 SWF 文件包含嵌入的媒体 (可通过其关联的类名称访问),或者 您要访问加载的 SWF 文件的方法,则这种方式会很有用。 以下示例假定可以访问定义了名为 welcome() 的公共方法的单独 Greeter.swf 文件。 package { import flash.display.Loader; import flash.display.Sprite; import flash.events.*; import flash.net.URLRequest; import flash.system.ApplicationDomain; import flash.system.LoaderContext; public class ApplicationDomainExample extends Sprite { private var ldr:Loader; public function ApplicationDomainExample() { ldr = new Loader(); var req:URLRequest = new URLRequest("Greeter.swf"); var ldrContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain); ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler); ldr.load(req, ldrContext); } private function completeHandler(event:Event):void { var myGreeter:Class = ApplicationDomain.currentDomain.getDefinition("Greeter") as Class; var myGreeter:Greeter = Greeter(event.target.content); var message:String = myGreeter.welcome("Tommy"); trace(message); // Hello, Tommy } } } 另请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考的 ApplicationDomain 类示例。 使用应用程序域时,还要记住以下几点: • SWF 文件中的所有代码被定义为存在于应用程序域中。主应用程序在 “ 当前域 ” 中运行。“ 系统域 ” 中包含所有应用程序域 (包括当前域),也就是包含所有 Flash Player 类。 • 所有应用程序域 (除系统域外)都有关联的父域。主应用程序的应用程序域的父域是系统域。已加载的类仅在其父级中没 有相关定义时才进行定义。不能用较新的定义覆盖已加载类的定义。 下图显示了某个应用程序在单个域 (domain1.com) 中加载多个 SWF 文件的内容。根据加载内容的不同,可以使用不同的应 用程序域。紧跟的文本说明用于为应用程序中的每个 SWF 文件设置适当应用程序域的逻辑。124ACTIONSCRIPT 3.0 开发人员指南 使用应用程序域 上次更新 2014/12/1 A. 用法 A B. 用法 B C. 用法 C 主应用程序文件为 application1.swf。它包含从其他 SWF 文件加载内容的 Loader 对象。在此方案下,当前域为 Application domain 1。用法 A、用法 B 和用法 C 说明了为应用程序中的每个 SWF 文件设置适当应用程序域的不同方法。 用法 A 通过创建系统域的子级划分子级 SWF 文件。在示意图中, Application domain 2 创建为系统域的子级。 application2.swf 文件在 Application domain 2 中加载,因此其类定义从 application1.swf 中定义的类中划分出来。 此方法的一个用处是使旧版应用程序能够动态加载相同应用程序的更新版本,而不会发生冲突。之所以不发生冲突,是因为尽 管使用的是同样的类名称,但它们划分到不同的应用程序域中。 下面的代码创建作为系统域子级的一个应用程序域,并使用该应用程序域开始加载一个 SWF: var appDomainA:ApplicationDomain = new ApplicationDomain(); var contextA:LoaderContext = new LoaderContext(false, appDomainA); var loaderA:Loader = new Loader(); loaderA.load(new URLRequest("application2.swf"), contextA); 用法 B: 在当前类定义中添加新的类定义。module1.swf 的应用程序域设置为当前域 (Application domain 1)。这可让您将新 的类定义添加到应用程序当前的一组类定义中。这可用于主应用程序的运行时共享库。加载的 SWF 被视为运行时共享库 (RSL)。使用此方法可以在应用程序启动之前使用预加载器加载 RSL。 下面的代码加载一个 SWF,同时将其应用程序域设置为当前域: var appDomainB:ApplicationDomain = ApplicationDomain.currentDomain; var contextB:LoaderContext = new LoaderContext(false, appDomainB); var loaderB:Loader = new Loader(); loaderB.load(new URLRequest("module1.swf"), contextB); 用法 C: 通过创建当前域的新子域,使用父级的类定义。 module3.swf 的应用程序域是当前域的子级,并且子级使用所有类的 父级的版本。此方法的一个用处可能是作为一个使用主应用程序的类型的多屏幕丰富 Internet 应用程序 (RIA) 模块,该模块作 为主应用程序的子级加载。如果能够确保所有类始终更新为向后兼容,并且正在加载的应用程序始终比其加载的软件的版本 新,则子级将使用父级版本。如果可以确保不继续拥有对子级 SWF 的引用,则拥有了新的应用程序域还使您能够卸载所有的 类定义以便于垃圾回收。 加载器 加载器 加载器 应用程序 加载器 舞台 模块 模块 应用程序域 1 安全域: domain1.com module1.swf module3.swf 应用程序域 3 A C B 模块 application2.swf application1.swf 应用程序域 2 mx.core.Application mx.core.Application125ACTIONSCRIPT 3.0 开发人员指南 使用应用程序域 上次更新 2014/12/1 此方法使加载的模块可以共享加载者的 singleton 对象和静态类成员。 下面的代码创建当前域的一个新子域,并使用该应用程序域开始加载一个 SWF: var appDomainC:ApplicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain); var contextC:LoaderContext = new LoaderContext(false, appDomainC); var loaderC:Loader = new Loader(); loaderC.load(new URLRequest("module3.swf"), contextC);126 上次更新 2014/12/1 第 10 章 : 显示编程 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 通过使用显示舞台上的显示对象,在 Adobe® ActionScript® 3.0 中对可视元素进行编程。例如,您可以使用 ActionScript 显 示编程 API 执行以下操作:添加、移动、删除并对显示对象排序、应用滤镜和蒙版、绘制矢量和位图图形以及执行三维转换。 显示编程使用的主类是 flash.display 包的一部分。 注: Adobe® AIR™ 提供了用于呈现和显示 HTML 内容的 HTMLoader 对象。 HTMLLoader 将 HTML DOM 的可视元素 呈现为单个显示对象。您不能通过 ActionScript 显示列表层次结构直接访问 DOM 的各个元素。 但是,您可使用由 HTMLLoader 提供的单独的 DOM API 来访问这些 DOM 元素。 显示编程的基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用 ActionScript 3.0 构建的每个应用程序都有一个由显示对象构成的层次,这个层次称为显示列表,如下所示。显示列表包 含应用程序中的所有可视元素。 显示对象 容器 显示对象显示对象 容器 显示对象 容器 SWF 文件 主类实例 Stage舞台 显示对象 容器显示对象 显示对象127ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 如图所示,显示元素分为以下一个或多个组: • Stage Stage 是包括显示对象的基础容器。每个应用程序都有一个 Stage 对象,其中包含所有的屏幕显示对象。舞台是顶级容器, 位于显示列表层次的顶部: 每个 SWF 文件都有一个关联的 ActionScript 类,该类称为 “SWF 文件的主类 ”。在 Flash Player 或 Adobe AIR 中打开 SWF 文件时,Flash Player 或 AIR 将调用该类的构造函数,并添加所创建的实例(始终是一种显示对象)作为 Stage 对象 的子级。 SWF 文件的主类始终用于扩展 Sprite 类 (有关详细信息,请参阅第 130 页的 “ 显示列表方法的优点 ”)。 可以通过任何 DisplayObject 实例的 stage 属性来访问舞台。有关详细信息,请参阅第 137 页的 “ 设置舞台属性 ”。 • 显示对象 在 ActionScript 3.0 中,在应用程序屏幕上出现的所有元素都属于 “ 显示对象 ” 类型。 flash.display 包中包含一个 DisplayObject 类,该类是一个由许多其他类扩展的基类。这些不同的类表示一些不同类型的显示对象,如矢量形状、影 片剪辑和文本字段等。有关这些类的概述,请参阅第 130 页的 “ 显示列表方法的优点 ”。 • 显示对象容器 显示对象容器是一些特殊类型的显示对象,这些显示对象除了有自己的可视表示形式之外,还可以包含也是显示对象的子对 象。 DisplayObjectContainer 类是 DisplayObject 类的子类。 DisplayObjectContainer 对象可以在其 “ 子级列表 ” 中包含 多个显示对象。例如,下图显示一种称为 Sprite 的 DisplayObjectContainer 对象,其中包含各种显示对象: A. SimpleButton 对象。此类显示对象有不同的 “ 弹起 ”、“ 按下 ” 和 “ 指针经过 ” 状态。 B. Bitmap 对象。本例中,Bitmap 对象是通过 Loader 对 象从外部 JPEG 加载的。 C. Shape 对象。“ 图片帧 ” 包含一个在 ActionScript 中绘制的圆角矩形。此 Shape 对象有一个应用于它的 Drop Shadow 滤 镜。 D. 一个 TextField 对象。 在讨论显示对象的上下文中, DisplayObjectContainer 对象又称为 “ 显示对象容器 ” 或简称为 “ 容器 ”。如前所述,舞台 是显示对象容器。 尽管所有可视显示对象都从 DisplayObject 类继承,但每类显示对象都是 DisplayObject 类的一个特定子类。例如,有 Shape 类或 Video 类的构造函数,但没有 DisplayObject 类的构造函数。 重要概念和术语 以下参考列表包含您在对 ActionScript 图形进行编程时会遇到的重要术语: Alpha 表示颜色透明度(或者更准确地说,是不透明度)的颜色值。例如,Alpha 通道值为 60% 的颜色只显示其最大强度的 60%,即有 40% 是透明的。 A B DC128ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 位图图形 在计算机中定义为彩色像素网格 (行和列)的图形。通常,位图图形包括数码照片和类似图像。 混合模式 说明两个重叠的图像的内容应该如何交互的规范。通常,一个图像上面的另一个不透明图像会遮盖住下面的图像,因 此根本看不到该图像;但是,不同的混合模式会导致图像颜色以不同方式混合在一起,因此,生成的内容是两个图像的某种组 合形式。 显示列表 由 Flash Player 和 AIR 呈现为可见屏幕内容的显示对象的层次。舞台是显示列表的根,附加到舞台或其一个子项上 的所有显示对象构成了显示列表 (即使对象实际上并未呈现,例如,对象位于舞台边界以外)。 显示对象 表示 Flash Player 或 AIR 中的某些可视类型的内容的对象。显示列表中只能包含显示对象,所有显示对象类都是 DisplayObject 类的子类。 显示对象容器 一种特殊类型的显示对象,除了 (通常)具有自己的可视表示形式以外,还可以包含子显示对象。 SWF 文件的主类 定义 SWF 文件中最外层显示对象的行为的类,从概念上说,这是 SWF 文件自身的类。例如,对于在 Flash 创作工具中创建的 SWF,主类为文档类。它具有一个包含所有其他时间轴的 “ 主时间轴 ” ; SWF 文件的主类是将主时间轴作 为其实例的类。 蒙版 一种隐藏视图中图像的特定部分 (或相反,只允许显示图像的特定部分)的技术。遮罩图像部分将变为透明,因此,将 显示其下面的内容。此术语与画家所使用的遮蔽胶带非常相似,遮蔽胶带用于防止将颜料喷到某些区域上。 舞台 作为 SWF 中的所有可视内容的库或背景的可视容器。 转换 对图形的视觉特性的调整,例如旋转对象、更改其比例、倾斜或扭曲其形状或改变其颜色。 矢量图形 在计算机中定义为使用特定特性 (如粗细、长度、大小、角度以及位置)绘制的线条和形状的图形。 核心显示类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 的 flash.display 包中包括可在 Flash Player 或 AIR 中显示的可视对象的类。下图说明了这些核心显示对象 类的子类关系。 该图说明了显示对象类的类继承。请注意,其中某些类,尤其是 StaticText、 TextField 和 Video 类,不在 flash.display 包 中,但它们仍然是从 DisplayObject 类继承的。 MorphShape DisplayObject AVM1Movie Shape StaticText Video DisplayObjectContainer TextField Bitmap InteractiveObject SimpleButton StageLoader MovieClip Sprite129ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 扩展 DisplayObject 类的所有类都继承该类的方法和属性。有关详细信息,请参阅 第 132 页的 “DisplayObject 类的属性和方 法 ”。 可以实例化包含在 flash.display 包中的下列类的对象: • Bitmap — 使用 Bitmap 类可定义从外部文件加载或通过 ActionScript 呈示的位图对象。可以通过 Loader 类从外部文件 加载位图。可以加载 GIF、 JPG 或 PNG 文件。还可以创建包含自定义数据的 BitmapData 对象,然后创建使用该数据的 Bitmap 对象。可以使用 BitmapData 类的方法来更改位图,无论这些位图是加载的还是在 ActionScript 中创建的。有关 详细信息,请参阅第 165 页的 “ 加载显示对象 ” 和第 203 页的 “ 使用位图 ”。 • Loader — 使用 Loader 类可加载外部资源 (SWF 文件或图形)。有关详细信息,请参阅第 164 页的 “ 动态加载显示内容 ”。 • Shape — 使用 Shape 类可创建矢量图形,如矩形、直线、圆等。有关详细信息,请参阅第 185 页的 “ 使用绘图 API”。 • SimpleButton — SimpleButton 对象是在 Flash 创作工具中创建的按钮元件的 ActionScript 表示形式。SimpleButton 实例有四种按钮状态:弹起、按下、指针经过和点击测试 (响应鼠标和键盘事件的区域)。 • Sprite — Sprite 对象可包含它自己的图形,也可包含子显示对象。(Sprite 类用于扩展 DisplayObjectContainer 类)。 有关详细信息,请参阅第 133 页的 “ 使用显示对象容器 ” 和第 185 页的 “ 使用绘图 API”。 • MovieClip — MovieClip 对象是在 Flash 创作工具中创建的影片剪辑元件的 ActionScript 形式。实际上,MovieClip 与 Sprite 对象类似,不同的是它还有一个时间轴。有关详细信息,请参阅第 270 页的 “ 使用影片剪辑 ”。 下列类不在 flash.display 包中,这些类是 DisplayObject 类的子类: • TextField 类包括在 flash.text 包中,它是用于文本显示和输入的显示对象。有关详细信息,请参阅第 311 页的 “ 文本使用 基础知识 ”。 • flash.text.engine 包中包含的 TextLine 类是用于显示由 Flash 文本引擎和 Text Layout Framework 组成的文本行的显示 对象。有关详细信息,请参阅第 334 页的 “ 使用 Flash 文本引擎 ” 和 第 360 页的 “ 使用 Text Layout Framework”。 • Video 类包括在 flash.media 包中,它是用于显示视频文件的显示对象。有关详细信息,请参阅第 401 页的 “ 使用视频 ”。 flash.display 包中的下列类用于扩展 DisplayObject 类,但您不能创建这些类的实例。这些类而是用作其他显示对象的父类, 因此可将通用功能合并到一个类中。 • AVM1Movie — AVM1Movie 类用于表示在 ActionScript 1.0 和 2.0 中创作的已加载 SWF 文件。 • DisplayObjectContainer — Loader、Stage、Sprite 和 MovieClip 类均用于扩展 DisplayObjectContainer 类。有关详 细信息,请参阅第 133 页的 “ 使用显示对象容器 ”。 • InteractiveObject — InteractiveObject 是用于与鼠标和键盘交互的所有对象的基类。 SimpleButton、 TextField、 Loader、 Sprite、 Stage 和 MovieClip 对象是 InteractiveObject 类的所有子类。有关创建鼠标和键盘交互的详细信息, 请参阅第 473 页的 “ 用户交互的基础知识 ”。 • MorphShape — 这些对象是在 Flash 创作工具中创建补间形状时创建的。无法使用 ActionScript 实例化这些对象,但可 以从显示列表中访问它们。 • Stage — Stage 类用于扩展 DisplayObjectContainer 类。一个应用程序有一个 Stage 实例,该实例位于显示列表层次的顶 部。要访问 Stage,请使用任何 DisplayObject 实例的 stage 属性。有关详细信息,请参阅第 137 页的 “ 设置舞台属性 ”。 此外,flash.text 包中的 StaticText 类也用于扩展 DisplayObject 类,但不能在代码中创建它的实例。只能在 Flash 中创建静 态文本字段。 以下类不是显示对象或显示对象容器,也不会出现在显示列表中,但是会在舞台上显示图形。这些类将绘制成一个称为视口的 矩形,相对于舞台放置。 • StageVideo — StageVideo 类用于在可能时使用硬件加速显示视频内容。此类从 Flash Player 10.2 开始可用。有关详细 信息,请参阅第 433 页的 “ 使用 StageVideo 类来实现硬件加速呈现 ”。 • StageWebView — StageWebView 类用于显示 HTML 内容。此类从 AIR 2.5 开始可用。有关详细信息,请参阅 第 880 页的 “StageWebView 对象 ”。130ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 下面的 fl.display 类提供与 flash.display.Loader 和 LoaderInfo 类并行的功能。如果您在 Flash Professional 环境 (CS5.5 或 更高版本)中进行开发,请使用这些类而不是其 flash.display 中的对应类。在该环境中,使用这些类可以解决与 TLF 的 RSL 预加载有关的问题。有关详细信息,请参阅第 168 页的 “ 使用 ProLoader 和 ProLoaderInfo 类 ”。 • fl.display.ProLoader — 与 flash.display.Loader 类似 • fl.display.ProLoaderInfo — 与 flash.display.LoaderInfo 类似 显示列表方法的优点 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 3.0 中,不同类型的显示对象有不同的类。在 ActionScript 1.0 和 2.0 中,很多相同类型的对象都包括在一个 类 (即 MovieClip 类)中。 类的这种个性化处理方式和显示列表的分层次结构具有下列优点: • 呈示方式更为有效且减少了内存使用 • 改进了深度管理 • 完整遍历显示列表 • 列表外的显示对象 • 更便于创建显示对象的子类 呈示方式更为有效且文件较小 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 1.0 和 2.0 中,只可以在 MovieClip 对象中绘制形状。在 ActionScript 3.0 中,提供了可在其中绘制形状的 更简单的显示对象类。由于这些 ActionScript 3.0 显示对象类并不包括 MovieClip 对象中包含的全部方法和属性,因此给内 存和处理器资源造成的负担比较小。 例如,每个 MovieClip 对象都包括用于影片剪辑时间轴的属性,而 Shape 对象则不包括。用于管理时间轴的属性会使用大量 的内存和处理器资源。在 ActionScript 3.0 中,使用 Shape 对象可提高性能。与更复杂的 MovieClip 对象相比,Shape 对象 的开销更少。Flash Player 和 AIR 并不需要管理未使用的 MovieClip 属性,因此提高了速度,还减少了对象使用的内存空间。 改进了深度管理 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 1.0 和 2.0 中,通过线性深度管理方案和方法 (如 getNextHighestDepth())进行深度管理。 在 ActionScript 3.0 中提供了 DisplayObjectContainer 类,该类提供用于管理显示对象深度的更便捷的方法和属性。 在 ActionScript 3.0 中,当您将显示对象移到 DisplayObjectContainer 实例的子级列表中的新位置时,显示对象容器中的其 他子级会自动重新定位并在显示对象容器中分配相应的子索引位置。 此外,在 ActionScript 3.0 中,总是可以发现任何显示对象容器中的所有子对象。每个 DisplayObjectContainer 实例都有 numChildren 属性,用于列出显示对象容器中的子级数。由于显示对象容器的子级列表始终是索引列表,因此可以检查列表中 从索引位置 0 到最后一个索引位置 (numChildren - 1) 的所有对象。这不适用于 ActionScript 1.0 和 2.0 中 MovieClip 对象的 方法和属性。131ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 在 ActionScript 3.0 中,可以按顺序轻松遍历显示列表;显示对象容器子级列表的索引编号没有中断。遍历显示列表和管理对 象深度比在 ActionScript 1.0 和 2.0 中更容易。在 ActionScript 1.0 和 2.0 中,影片剪辑可以包含深度顺序有间歇中断的对象, 这可能导致难以遍历对象列表。在 ActionScript 3.0 中,显示对象容器的每个子级列表都在内部缓存为一个数组,这样按索引 查找的速度就非常快。遍历显示对象容器所有子级的速度也非常快。 在 ActionScript 3.0 中,还可以通过使用 DisplayObjectContainer 类的 getChildByName() 方法来访问显示对象容器中的子 级。 完整遍历显示列表 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 1.0 和 2.0 中,无法访问在 Flash 创作工具中绘制的某些对象(如矢量形状)。在 ActionScript 3.0 中,可以 访问显示列表中的所有对象,包括使用 ActionScript 创建的对象以及在 Flash 创作工具中创建的所有显示对象。有关详细信 息,请参阅第 136 页的 “ 遍历显示列表 ”。 列表外的显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 3.0 中,可以创建不在可视显示列表中的显示对象。这些对象称为 “ 列表外 ” 显示对象。仅当调用已添加到显 示列表中的 DisplayObjectContainer 实例的 addChild() 或 addChildAt() 方法时,才会将显示对象添加到可视显示列表中。 可以使用列表外的显示对象来组合复杂的显示对象,如有多个显示对象容器 (包含多个显示对象)的那些对象。通过将显示对 象放在列表外,可以组合复杂的对象,而不需要占用处理时间来呈示这些显示对象。然后在需要时可以在显示列表中添加列表 外的显示对象。此外,可以随意将显示对象容器的子级移入和移出显示列表以及移到显示列表中的任何需要位置。 更便于创建显示对象的子类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 1.0 和 2.0 中,通常必须在 SWF 文件中添加新的 MovieClip 对象才能创建基本形状或显示位图。在 ActionScript 3.0 中,DisplayObject 类包括许多内置子类,包括 Shape 和 Bitmap。由于 ActionScript 3.0 中的类更专用于 特定类型的对象,因此更易于创建内置类的基本子类。 例如,要在 ActionScript 2.0 中绘制一个圆,可以在实例化自定义类的对象时创建用于扩展 MovieClip 类的 CustomCircle 类。但是,该类还另外包括 MovieClip 类中不应用于该类的许多属性和方法 (如 totalFrames)。但在 ActionScript 3.0 中, 可以创建用于扩展 Shape 对象的 CustomCircle 类,但该类不包括 MovieClip 类中包含的不相关的属性和方法。下面的代码 显示了 CustomCircle 类的一个示例:132ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 import flash.display.*; public class CustomCircle extends Shape { var xPos:Number; var yPos:Number; var radius:Number; var color:uint; public function CustomCircle(xInput:Number, yInput:Number, rInput:Number, colorInput:uint) { xPos = xInput; yPos = yInput; radius = rInput; color = colorInput; this.graphics.beginFill(color); this.graphics.drawCircle(xPos, yPos, radius); } } 使用显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 现在您已了解了舞台、显示对象、显示对象容器和显示列表的基本概念,本部分将为您提供有关在 ActionScript 3.0 中使用显 示对象的一些更具体的信息。 DisplayObject 类的属性和方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 所有显示对象都是 DisplayObject 类的子类,同样它们还会继承 DisplayObject 类的属性和方法。继承的属性是适用于所有 显示对象的基本属性。例如,每个显示对象都有 x 属性和 y 属性,用于指定对象在显示对象容器中的位置。 您不能使用 DisplayObject 类构造函数来创建 DisplayObject 实例。必须创建另一种对象 (属于 DisplayObject 类的子类的 对象,如 Sprite)才能使用 new 运算符来实例化对象。此外,如果要创建自定义显示对象类,还必须创建具有可用构造函数的 其中一个显示对象子类的子类 (如 Shape 类或 Sprite 类)。有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中的 DisplayObject 类说明。 在显示列表中添加显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 实例化显示对象时,在将显示对象实例添加到显示列表上的显示对象容器之前,显示对象不会出现屏幕上 (即在舞台上)。例 如,在下面的代码中,如果省略了最后一行代码,则 myText TextField 对象不可见。在最后一行代码中,this 关键字必须引用 已添加到显示列表中的显示对象容器。 import flash.display.*; import flash.text.TextField; var myText:TextField = new TextField(); myText.text = "Buenos dias."; this.addChild(myText);133ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 当在舞台上添加任何可视元素时,该元素会成为 Stage 对象的 “ 子级 ”。应用程序中加载的第一个 SWF 文件 (例如,HTML 页中嵌入的文件)会自动添加为 Stage 的子级。它可以是扩展 Sprite 类的任何类型的对象。 不是 使用 ActionScript (例如,通过在 Flex MXML 文件中添加 MXML 标签或在 Flash Professional 的舞台上放置项目) 创建的任何显示对象都会添加到显示列表中。尽管没有通过 ActionScript 添加这些显示对象,但仍可通过 ActionScript 访问 它们。例如,下面的代码将调整在创作工具中 (不是通过 ActionScript)添加的名为 button1 的对象的宽度: button1.width = 200; 使用显示对象容器 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如果从显示列表中删除某个 DisplayObjectContainer 对象,或者以其他某种方式移动该对象或对其进行变形处理,则会同时 删除、移动 DisplayObjectContainer 中的每个显示对象或对其进行变形处理。 显示对象容器本身就是一种显示对象,它可以添加到其他显示对象容器中。例如,下图显示的是显示对象容器 pictureScreen, 它包含一个轮廓形状和四个其他显示对象容器 (类型为 PictureFrame): A. 定义 pictureScreen 显示对象容器边框的形状 B. 作为 pictureScreen 对象的子级的四个显示对象容器 要使某一显示对象出现在显示列表中,必须将该显示对象添加到显示列表上的显示对象容器中。使用容器对象的 addChild() 方 法或 addChildAt() 方法可执行此操作。例如,如果下面的代码没有最后一行,将不会显示 myTextField 对象: A B134ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 var myTextField:TextField = new TextField(); myTextField.text = "hello"; this.root.addChild(myTextField); 在此代码范例中, this.root 指向包含该代码的 MovieClip 显示对象容器。在实际代码中,可以指定其他容器。 使用 addChildAt() 方法可将子级添加到显示对象容器的子级列表中的特定位置。子级列表中这些从 0 开始的索引位置与显示对 象的分层 (从前到后顺序)有关。例如,请考虑下列三个显示对象。每个对象都是从称为 Ball 的自定义类创建的。 使用 addChildAt() 方法可以调整这些显示对象在容器中的分层。例如,请看以下代码: ball_A = new Ball(0xFFCC00, "a"); ball_A.name = "ball_A"; ball_A.x = 20; ball_A.y = 20; container.addChild(ball_A); ball_B = new Ball(0xFFCC00, "b"); ball_B.name = "ball_B"; ball_B.x = 70; ball_B.y = 20; container.addChild(ball_B); ball_C = new Ball(0xFFCC00, "c"); ball_C.name = "ball_C"; ball_C.x = 40; ball_C.y = 60; container.addChildAt(ball_C, 1); 执行此代码后,显示对象在 container DisplayObjectContainer 对象中的定位如下所示。请注意对象的分层。 要重新将对象定位到显示列表的顶部,只需重新将其添加到列表中。例如,在前面的代码后,要将 ball_A 移到堆栈的顶部,请 使用下面的代码行: container.addChild(ball_A); 此代码可有效地将 ball_A 从它在 container 的显示列表中的位置删除,然后将它重新添加到列表的顶部,最终的结果是将它移 到堆栈的顶部。 可以使用 getChildAt() 方法来验证显示对象的图层顺序。getChildAt() 方法根据您向容器传递的索引编号返回容器的子对象。例 如,下面的代码显示 container DisplayObjectContainer 对象的子级列表中不同位置的显示对象的名称:135ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 trace(container.getChildAt(0).name); // ball_A trace(container.getChildAt(1).name); // ball_C trace(container.getChildAt(2).name); // ball_B 如果从父容器的子级列表中删除了一个显示对象,则列表中更高位置的每一个元素在子索引中会分别下移一个位置。例如,接 着前面的代码,下面的代码显示如果删除子级列表中位置较低的一个显示对象,container DisplayObjectContainer 中位置 2 的显示对象如何移到位置 1: container.removeChild(ball_C); trace(container.getChildAt(0).name); // ball_A trace(container.getChildAt(1).name); // ball_B removeChild() 和 removeChildAt() 方法并不完全删除显示对象实例。这两种方法只是从容器的子级列表中删除显示对象实例。 该实例仍可由另一个变量引用。(请使用 delete 运算符完全删除对象。) 由于显示对象只有一个父容器,因此只能在一个显示对象容器中添加显示对象的实例。例如,下面的代码说明了显示对象 tf1 只能存在于一个容器中 (本例中为 Sprite,它扩展 DisplayObjectContainer 类): tf1:TextField = new TextField(); tf2:TextField = new TextField(); tf1.name = "text 1"; tf2.name = "text 2"; container1:Sprite = new Sprite(); container2:Sprite = new Sprite(); container1.addChild(tf1); container1.addChild(tf2); container2.addChild(tf1); trace(container1.numChildren); // 1 trace(container1.getChildAt(0).name); // text 2 trace(container2.numChildren); // 1 trace(container2.getChildAt(0).name); // text 1 如果将包含在一个显示对象容器中的显示对象添加到另一个显示对象容器中,则会从第一个显示对象容器的子级列表中删除该 显示对象。 除了上面介绍的方法之外, DisplayObjectContainer 类还定义了用于使用子显示对象的几个方法,其中包括: • contains():确定显示对象是否是 DisplayObjectContainer 的子级。 • getChildByName():按名称检索显示对象。 • getChildIndex():返回显示对象的索引位置。 • setChildIndex():更改子显示对象的位置。 • removeChildren():删除多个子显示对象。 • swapChildren():交换两个显示对象的前后顺序。 • swapChildrenAt():交换两个显示对象的前后顺序 (由其索引值指定)。 有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中的相关条目。 回想一下,不在显示列表中的显示对象 (即不包括在作为舞台子级的显示对象容器中的显示对象)称为 “ 列表外 ” 显示对象。136ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 遍历显示列表 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如您所见,显示列表是一个树结构。树的顶部是舞台,它可以包含多个显示对象。那些本身就是显示对象容器的显示对象可以 包含其他显示对象或显示对象容器。 DisplayObjectContainer 类包括通过显示对象容器的子级列表遍历显示列表的属性和方法。例如,考虑下面的代码,其中在 container 对象 (该对象为 Sprite, Sprite 类用于扩展 DisplayObjectContainer 类)中添加了两个显示对象 title 和 pict: var container:Sprite = new Sprite(); var title:TextField = new TextField(); title.text = "Hello"; var pict:Loader = new Loader(); var url:URLRequest = new URLRequest("banana.jpg"); pict.load(url); pict.name = "banana loader"; container.addChild(title); container.addChild(pict); getChildAt() 方法返回显示列表中特定索引位置的子级: trace(container.getChildAt(0) is TextField); // true 您也可以按名称访问子对象。每个显示对象都有一个名称属性;如果没有指定该属性, Flash Player 或 AIR 会指定一个默认 值,如 "instance1"。例如,下面的代码说明了如何使用 getChildByName() 方法来访问名为 "banana loader" 的子显示对象: trace(container.getChildByName("banana loader") is Loader); // true 与使用 getChildAt() 方法相比,使用 getChildByName() 方法会导致性能降低。 显示对象 容器 显示对象显示对象 容器 显示对象 容器 SWF 文件 主类实例 Stage舞台 显示对象 容器显示对象 显示对象137ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 由于显示对象容器可以包含其他显示对象容器作为其显示列表中的子对象,因此您可将应用程序的完整显示列表作为树来遍 历。例如,在前面说明的代码摘录中,完成 pict Loader 对象的加载操作后,pict 对象将加载一个子显示对象,即位图。要访问 此位图显示对象,可以编写 pict.getChildAt(0)。还可以编写 container.getChildAt(0).getChildAt(0) (由于 container.getChildAt(0) == pict)。 下面的函数提供了显示对象容器中显示列表的缩进式 trace() 输出: function traceDisplayList(container:DisplayObjectContainer,indentString:String = ""):void { var child:DisplayObject; for (var i:uint=0; i < container.numChildren; i++) { child = container.getChildAt(i); trace(indentString, child, child.name); if (container.getChildAt(i) is DisplayObjectContainer) { traceDisplayList(DisplayObjectContainer(child), indentString + "") } } } Adobe Flex 如果使用 Flex,您应了解 Flex 定义了许多组件显示对象类,这些类会覆盖 DisplayObjectContainer 类的显示列表访问方 法。例如, mx.core 包的 Container 类会覆盖 DisplayObjectContainer 类(Container 类所扩展的类)的 addChild() 方法 和其他方法。就 addChild() 方法而言,该类覆盖该方法的结果是,在 Flex 中,所有类型的显示对象都不能添加到 Container 实例。在本例中,被覆盖的方法要求所添加的子对象为 mx.core.UIComponent 对象类型。 设置舞台属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Stage 类用于覆盖 DisplayObject 类的大多数属性和方法。如果调用其中一个被覆盖的属性或方法,Flash Player 和 AIR 会引 发异常。例如,Stage 对象不具有 x 或 y 属性,因为作为应用程序的主容器,该对象的位置是固定的。x 和 y 属性是指显示对象 相对于其容器的位置,因为舞台没有包含在其他显示对象容器中,所以这些属性不适用。 注: Stage 类的某些属性和方法只适用于与加载的第一个 SWF 文件在同一个安全沙箱中的显示对象。有关详细信息,请参阅 第 912 页的 “Stage 安全性 ”。 控制播放帧速率 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Stage 类的 frameRate 属性用于设置加载到应用程序中的所有 SWF 文件的帧速率。有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考。 控制舞台缩放 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当调整呈示 Flash Player 或 AIR 的屏幕部分的大小时,运行时会自动调整舞台内容来加以补偿。Stage 类的 scaleMode 属性可 确定如何调整舞台内容。此属性可以设置为 4 个不同值,如 flash.display.StageScaleMode 类中的常量所定义: • StageScaleMode.EXACT_FIT 缩放 SWF 以填满新舞台尺寸,而不考虑原来的内容高宽比。宽度和高度的缩放系数可能会有 所不同,因此当舞台的高宽比发生更改时,显示的内容有可能随之压扁或拉长。138ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 • StageScaleMode.SHOW_ALL 会在保持内容高宽比的前提下,缩放 SWF 以适应新舞台。这种缩放模式可完整显示所有内 容,但是可能导致出现 “ 邮箱 ” 式边框,就像使用标准电视收看宽屏电影时出现的黑色长条。 • StageScaleMode.NO_BORDER 会在保持内容高宽比的前提下,缩放 SWF 以填满新舞台。这种缩放模式可以充分利用舞台 显示区域,但可能导致裁切。 • StageScaleMode.NO_SCALE — 不缩放 SWF。 如果新舞台较小,内容将遭到裁切;如果较大,所增加的空间将显示为空 白。 仅在 StageScaleMode.NO_SCALE 缩放模式中,Stage 类的 stageWidth 和 stageHeight 属性才能用于确定窗口调整大小后的 实际像素尺寸。(在其他缩放模式中, stageWidth 和 stageHeight 属性始终反映的是 SWF 的原始宽度和高度。)此外,当 scaleMode 设置为 StageScaleMode.NO_SCALE 并且调整了 SWF 文件大小时,将调度 Stage 类的 resize 事件,以允许您进行 相应地调整。 因此,将 scaleMode 设置为 StageScaleMode.NO_SCALE 可以更好地控制如何根据需要调整屏幕内容以适合窗口大小。例 如,在包含视频和控制栏的 SWF 中,您可能希望在调整舞台大小时控制栏的大小保持不变,而仅更改视频窗口大小以适应 舞台大小的更改。以下示例中演示了这一点: // mainContent is a display object containing the main content; // it is positioned at the top-left corner of the Stage, and // it should resize when the SWF resizes. // controlBar is a display object (e.g. a Sprite) containing several // buttons; it should stay positioned at the bottom-left corner of the // Stage (below mainContent) and it should not resize when the SWF // resizes. import flash.display.Stage; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; var swfStage:Stage = mainContent.stage; swfStage.scaleMode = StageScaleMode.NO_SCALE; swfStage.align = StageAlign.TOP_LEFT; swfStage.addEventListener(Event.RESIZE, resizeDisplay); function resizeDisplay(event:Event):void { var swfWidth:int = swfStage.stageWidth; var swfHeight:int = swfStage.stageHeight; // Resize the main content area var newContentHeight:Number = swfHeight - controlBar.height; mainContent.height = newContentHeight; mainContent.scaleX = mainContent.scaleY; // Reposition the control bar. controlBar.y = newContentHeight; } 设置 AIR 窗口的舞台缩放模式 舞台 scaleMode 属性确定在调整窗口大小时舞台如何缩放和剪裁子显示对象。在 AIR 中只应使用 noScale 模式。在此模式中不 缩放舞台。舞台的大小直接随窗口的范围变化。如果将窗口调小,则可能会剪裁对象。 舞台缩放模式旨在用于您无法始终控制舞台大小或高宽比的环境,例如 Web 浏览器。当舞台与应用程序的理想大小或高宽比 不匹配时,使用这些模式可以选择最好的折衷方案。在 AIR 中,您始终能够控制舞台,因此在大多数情况下,重新放置您的内 容或调整窗口尺寸可以获得比启用舞台缩放更好的结果。139ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 在浏览器中,以及对于初始 AIR 窗口,窗口大小与初始缩放系数之间的关系是从所加载的 SWF 文件中读取的。然而,在创建 NativeWindow 对象时,AIR 选择窗口大小和缩放系数 72:1 之间的任意关系。因此如果窗口为 72x72 像素,则以 10x10 像素 的正确大小绘制添加到窗口的 10x10 矩形。但是,如果窗口为 144x144 像素,则 10x10 像素的矩形会缩放为 20x20 像素。如 果您坚持对窗口舞台使用 scaleMode 而不是 noScale,则可以通过将窗口中的任何显示对象的缩放系数都设置为 72 像素与舞台 的当前宽度和高度之比加以补偿。例如,以下代码计算名为 client 的显示对象所需的缩放系数: if(newWindow.stage.scaleMode != StageScaleMode.NO_SCALE){ client.scaleX = 72/newWindow.stage.stageWidth; client.scaleY = 72/newWindow.stage.stageHeight; } 注: Flex 和 HTML 窗口自动将舞台 scaleMode 设置为 noScale。更改 scaleMode 会打乱这些窗口类型中所使用的自动布局机 制。 使用全屏模式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用全屏模式可以将影片的舞台设置为填充查看者的整个显示器,而不包含任何边框或菜单。 Stage 类的 displayState 属性用于 切换 SWF 的全屏模式。可以将 displayState 属性设置为由 flash.display.StageDisplayState 类中的常量定义的其中一个值。若 要打开全屏模式,请将 displayState 属性设置为 StageDisplayState.FULL_SCREEN: stage.displayState = StageDisplayState.FULL_SCREEN; 若要启用全屏交互模式 (Flash Player 11.3 中的新增功能),请将 displayState 属性设置为 StageDisplayState.FULL_SCREEN_INTERACTIVE: stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE; 在 Flash Player 中,只能通过 ActionScript 响应鼠标单击 (包括右键单击)或按键来启动全屏模式。在应用程序安全沙箱中 运行的 AIR 内容不要求在响应用户手势时进入全屏模式。 若要退出全屏模式,请将 displayState 属性设置为 StageDisplayState.NORMAL。 stage.displayState = StageDisplayState.NORMAL; 此外,用户可以通过将焦点切换到其他窗口或使用以下组合键之一退出全屏模式:Esc 键 (所有平台)、 Ctrl-W (Windows)、 Command-W (Mac) 或 Alt-F4 (Windows)。 启用 Flash Player 中的全屏模式 若要为 HTML 页中嵌入的 SWF 文件启用全屏模式,必须在嵌入 Flash Player 的 HTML 代码中加入含有名称 allowFullScreen 和值 true 的 param 标签和 embed 属性,如下所示: ... 在 Flash 创作工具中选择 “ 文件 ”->“ 发布设置 ”,并在 “ 发布设置 ” 对话框中的 “HTML” 选项卡上选择 “ 仅 Flash - 允许全 屏 ” 模板。 在 Flex 中,确保 HTML 模板包含支持全屏的 标签。 如果要在网页中使用 JavaScript 来生成 SWF 嵌入标签,则必须更改 JavaScript 以添加 allowFullScreen param 标签和属性。例 如,如果 HTML 页使用 AC_FL_RunContent() 函数(在由 Flash Professional 和 Flash Builder 生成的 HTML 页中使用), 则应在该函数调用中添加 allowFullScreen 参数,如下所示:140ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 AC_FL_RunContent( ... 'allowFullScreen','true', ... ); //end AC code 这不适用于在独立 Flash Player 中运行的 SWF 文件。 注: 如果将窗口模式 (HTML 中的 wmode)设置为不透明无窗口 (opaque) 或透明无窗口 (transparent),则全屏窗口始终 是不透明的 对浏览器中的 Flash Player 使用全屏模式时还有一些安全方面的限制。第 894 页的 “ 安全性 ” 中对这些限制进行了说明。 在 Flash Player 11.3 和更高版本中启用全屏交互模式 Flash Player 11.3 和更高版本支持全屏交互模式,该模式可实现对所有键盘键的完全支持 (Esc 除外,使用该键将退出全屏交 互模式)。全屏交互模式对于游戏非常有用(例如,支持多人游戏聊天或第一人射击游戏中的 WASD 键盘控件。) 若要为 HTML 页中嵌入的 SWF 文件启用全屏交互模式,必须在嵌入 Flash Player 的 HTML 代码中加入含有名称 allowFullScreenInteractive 和值 true 的 param 标签和 embed 属性,如下所示: ... 在 Flash 创作工具中选择 “ 文件 ”->“ 发布设置 ”,并在 “ 发布设置 ” 对话框中的 “HTML” 选项卡上选择 “ 仅 Flash - 允许全 屏 ” 模板。 在 Flash Builder 和 Flex 中,确保 HTML 模板包括支持全屏交互模式的 标签。 如果要在网页中使用 JavaScript 来生成 SWF 嵌入标签,则必须更改 JavaScript 以添加 allowFullScreenInteractive param 标签 和属性。例如,如果 HTML 页使用 AC_FL_RunContent() 函数 (在由 Flash Professional 和 Flash Builder 生成的 HTML 页中使用),则应在该函数调用中添加 allowFullScreenInteractive 参数,如下所示: AC_FL_RunContent( ... 'allowFullScreenInteractive','true', ... ); //end AC code 这不适用于在独立 Flash Player 中运行的 SWF 文件。 全屏舞台大小和缩放 Stage.fullScreenHeight 和 Stage.fullScreenWidth 属性返回在转为全屏大小时所使用的显示器的高度和宽度 (如果是立即进入全 屏状态)。在您检索到这些值之后,但在进入全屏模式之前,如果用户有机会将浏览器从一台显示器移至另一台显示器,则这 些值可能不正确。如果是在将 Stage.displayState 属性设置为 StageDisplayState.FULL_SCREEN 的同一个事件处理函数中检索这 些值,则这些值正确。对于拥有多台显示器的用户, SWF 内容扩大时只会填充一台显示器。 Flash Player 和 AIR 使用度量信 息来确定哪个显示器包含 SWF 的最大部分内容,然后使用该显示器提供全屏模式。fullScreenHeight 和 fullScreenWidth 属 性仅反映出显示器用于全屏模式的大小。有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中的 Stage.fullScreenHeight 和 Stage.fullScreenWidth。 全屏模式的舞台缩放行为与正常模式下的相同;缩放比例由 Stage 类的 scaleMode 属性控制。如果 scaleMode 属性设置为 StageScaleMode.NO_SCALE,则舞台的 stageWidth 和 stageHeight 属性会发生更改,以反映 SWF 所占用的屏幕区域的大小 (在本例中为整个屏幕);如果在浏览器中查看,则此属性的 HTML 参数用于控制该设置。 打开或关闭全屏模式时,可以使用 Stage 类的 fullScreen 事件来进行检测和响应。例如,进入或退出全屏模式时,您可能需要 重新定位、添加或删除屏幕中的项目,如本例中所示:141ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 import flash.events.FullScreenEvent; function fullScreenRedraw(event:FullScreenEvent):void { if (event.fullScreen) { // Remove input text fields. // Add a button that closes full-screen mode. } else { // Re-add input text fields. // Remove the button that closes full-screen mode. } } mySprite.stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenRedraw); 正如此代码所示, fullScreen 事件的事件对象是 flash.events.FullScreenEvent 类的实例,它包含指示是启用 (true) 还是禁用 (false) 全屏模式的 fullScreen 属性。 全屏模式下的键盘支持 当 Flash Player 在浏览器中运行时,全屏模式下将禁用所有与键盘相关的 ActionScript,如 TextField 实例中的键盘事件和文 本输入。但有一些例外 (启用的键): • 经过挑选的非打印键,尤其是方向键、空格键和 Tab 键 • 用于终止全屏模式的快捷键:Esc (Windows 和 Mac)、 Ctrl-W (Windows)、 Command-W (Mac) 和 Alt-F4 对于在独立 Flash Player 或 AIR 中运行的 SWF 内容,不存在这些限制。 AIR 支持允许键盘输入的交互式全屏模式。 全屏模式下的鼠标支持 默认情况下,全屏模式下的鼠标事件的工作方式与未处于全屏模式时相同。但是,在全屏模式下,您可以选择设置 Stage.mouseLock 属性,以启用鼠标锁定。鼠标锁定将禁用光标,且启用没有限制的鼠标移动。 注: 您只能在桌面应用程序的全屏模式下启用鼠标锁定。如果在未处于全屏模式的应用程序上或为移动设备上的应用程序设置 鼠标锁定,则会引发异常。 在下列情况下鼠标锁定被自动禁用,鼠标光标再次显示: • 用户使用 Esc 键 (所有平台)、 Ctrl-W (Windows)、 Command-W (Mac) 或 Alt-F4 (Windows) 退出全屏模式。 • 应用程序窗口丢失焦点。 • 任何设置 UI 都可见,包括所有隐私对话框。 • 显示本机对话框,如文件上传对话框。 与鼠标移动相关的事件,例如 mouseMove 事件,使用 MouseEvent 类表示事件对象。禁用鼠标锁定时,使用 MouseEvent.localX 和 MouseEvent.localY 属性确定鼠标的位置。启用鼠标锁定时,使用 MouseEvent.movementX 和 MouseEvent.movementY 属性确定鼠标的位置。 movementX 和 movementY 属性包含自上一个事件以来的鼠标位置的变化,而 不是鼠标位置的绝对坐标。 全屏模式下的硬件缩放 使用 Stage 类的 fullScreenSourceRect 属性可以设置 Flash Player 或 AIR 以将舞台的特定区域放大为全屏幕模式。 Flash Player 和 AIR 使用用户计算机上的图形和视频卡进行硬件缩放 (如果可用),一般来说显示内容的速度要快于软件缩放。 若要利用硬件缩放功能,请将整个舞台或部分舞台设置为全屏模式。 以下 ActionScript 3.0 代码将整个舞台设置为全屏模式:142ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 import flash.geom.*; { stage.fullScreenSourceRect = new Rectangle(0,0,320,240); stage.displayState = StageDisplayState.FULL_SCREEN; } 如果将此属性设置为有效矩形并将 displayState 属性设置为全屏模式, Flash Player 和 AIR 对指定区域进行缩放。 ActionScript 中的实际舞台大小 (以像素为单位)不会发生改变。 Flash Player 和 AIR 对矩形大小强制规定了最小限制,以 容纳标准的 “ 按 Esc 退出全屏模式 ” 消息。通常,此限制大约为 260 x 30 个像素,但可能因平台和 Flash Player 版本而异。 仅当 Flash Player 或 AIR 处于非全屏模式时,才能设置 fullScreenSourceRect 属性。若要正确使用此属性,请先设置此属 性,然后再将 displayState 属性设置为全屏模式。 若要启用缩放功能,请将 fullScreenSourceRect 属性设置为矩形对象。 stage.fullScreenSourceRect = new Rectangle(0,0,320,240); 若要禁用缩放功能,请将 fullScreenSourceRect 属性设置为 null。 stage.fullScreenSourceRect = null; 若要利用 Flash Player 中的所有硬件加速功能,请通过 Flash Player 的 “ 设置 ” 对话框将其启用。若要加载该对话框,请在浏 览器的 Flash Player 内容中单击右键 (Windows) 或按住 Control 的同时单击 (Mac)。选择 “ 显示 ” 选项卡 (第一个选项 卡),然后选中复选框:“ 启用硬件加速 ”。 直接窗口模式和 GPU 合成窗口模式 Flash Player 10 引入了两种窗口模式:直接模式和 GPU 合成模式。可以通过 Flash 创作工具中的发布设置启用这些模式。 AIR 中不支持这两种模式。若要利用这两种模式,必须为 Flash Player 启用硬件加速。 直接模式使用最快、最直接的路径将图形推送至屏幕,这有利于视频播放。 GPU 合成模式使用显卡中的图形处理单元来加速合成。视频合成是层叠多幅图像以创建单幅视频图像的过程。当采用 GPU 加 速合成时,这可提高 YUV 转换、颜色校正、旋转或缩放以及混合的性能。YUV 转换是指将用于传输的合成模拟信号转换为视 频摄像头和显示器所使用的 RGB (红、绿、蓝)颜色模型的颜色转换。使用 GPU 加速合成可减少内存占用量以及 CPU 的计 算负担。这还促成了标准清晰度视频更平滑的播放。 在实施这些窗口模式时应谨慎小心。使用 GPU 合成可能消耗很多内存资源和 CPU 资源。如果某些操作 (如混合模式、过 滤、剪裁或遮罩)无法在 GPU 中执行,则可以通过软件来完成。 Adobe 建议在使用这些模式时,应限制为每个 HTML 页面 一个 SWF 文件,并且不应对横幅启用这些模式。 Flash“ 测试影片 ” 工具不使用硬件加速,但是可通过 “ 发布预览 ” 选项来使 用硬件加速。 将 SWF 文件中的帧速率设置为高于 60 (最大屏幕刷新率)将不起作用。将帧速率设置为 50 到 55 之间将允许放弃的帧,这 种情况经常由于各种原因而发生。 使用直接模式对于 Windows 需要 Microsoft DirectX 9 以及 128 MB VRAM,对于 Apple Macintosh Mac OS X 10.2 版 或更高版本需要 OpenGL。GPU 合成模式需要在具有 128 MB VRAM 的 Windows 上支持 Microsoft DirectX 9 和 Pixel Shader 2.0。在 Mac OS X 和 Linux 上,GPU 合成模式需要 OpenGL 1.5 以及多种 OpenGL 扩展(帧缓冲区对象、多纹理、 着色器对象、着色语言和片段着色器)。 可通过 Flash“ 发布设置 ” 对话框,使用 “Flash” 选项卡上的 “ 硬件加速 ” 菜单,为每个 SWF 单独激活 direct 和 gpu 加速模 式。如果选择 “ 无 ”,则窗口模式将按照 “HTML” 选项卡上 “ 窗口模式 ” 设置所指定的项,转换为 default、 transparent 或 opaque。143ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 处理显示对象的事件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 DisplayObject 类从 EventDispatcher 类继承。这意味着,每个显示对象都可完全参与到事件模型中 (在第 106 页的 “ 处理 事件 ” 中介绍)。每个显示对象都可使用其 addEventListener() 方法 (继承自 EventDispatcher 类)来侦听特定的事件,但仅 当侦听对象是该事件的事件流的一部分时才能实现此功能。 当 Flash Player 或 AIR 调度某个事件对象时,该事件对象会执行从舞台到发生事件的显示对象的往返行程。例如,如果用户 单击名为 child1 的显示对象, Flash Player 会沿显示列表层次将事件对象从舞台向下调度到 child1 显示对象。 从概念上说,事件流分为三个阶段,如下图所示: 有关详细信息,请参阅第 106 页的 “ 处理事件 ”。 使用显示对象事件时需要记住的一个重要问题是:从显示列表中删除显示对象时,事件侦听器的存在将会对是否从内存中自动 删除显示对象 (垃圾回收)产生影响。如果显示对象拥有订阅为其事件的侦听器的对象,即使从显示列表中删除了显示对象, 也不会从内存中删除显示对象,因为显示对象仍然拥有对这些侦听器对象的引用。有关详细信息,请参阅第 116 页的 “ 管理事 件侦听器 ”。 选择 DisplayObject 子类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可选的子类有多个,使用显示对象时要做出的一个重要决策是:每个显示对象的用途是什么。以下原则可以帮助您作出决策。 无论是需要类实例,还是选择要创建的类的基类,这些建议都适用: • 如果不需要可作为其他显示对象的容器的对象 (即只需要用作独立屏幕元素的对象),请根据用途选择 DisplayObject 或 InteractiveObject 两个子类中的一个: • 用于显示位图图像的 Bitmap。 • 用于添加文本的 TextField。 • 用于显示视频的 Video。 • 用于绘制屏幕内容的 “ 画布 ” 的 Shape。特别是,如果要创建用于在屏幕上绘制形状的实例,而该实例不是其他显示对象 的容器,则使用 Shape 比使用 Sprite 或 MovieClip 有明显的性能优势。 • 用于由 Flash 创作工具创建的项的 MorphShape、 StaticText 或 SimpleButton。(无法以编程方式创建这些类的实 例,但可以通过创建具有这些数据类型的变量来引用使用 Flash 创作工具创建的项。) • 如果需要使用变量来引用主舞台,请使用 Stage 类作为其数据类型。 舞台 父节点 Child1 节点 Child2 节点 捕获 阶段 冒泡 阶段 目标阶段144ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 • 如果需要容器来加载外部 SWF 文件或图像文件,请使用 Loader 实例。加载的内容将作为 Loader 实例的子级添加到显示 列表中。其数据类型将取决于加载内容的性质,如下所示: • 加载的图像将是 Bitmap 实例。 • 使用 ActionScript 3.0 编写的已加载 SWF 文件将是 Sprite 或 MovieClip 实例 (或这些类的子类的实例,由内容创建 者指定)。 • 使用 ActionScript 1.0 或 ActionScript 2.0 编写的已加载 SWF 文件将是 AVM1Movie 实例。 • 如果需要将一个对象用作其他显示对象的容器 (无论是否还要使用 ActionScript 在显示对象上进行绘制),请选择其中一 个 DisplayObjectContainer 子类: • 如果对象是只使用 ActionScript 创建的,或者如果对象作为只使用 ActionScript 创建和处理的自定义显示对象的基 类,请选择 Sprite。 • 如果要通过创建变量来引用在 Flash 创作工具中创建的影片剪辑元件,请选择 MovieClip。 • 如果要创建的类与 Flash 库中的影片剪辑元件关联,请选择其中一个 DisplayObjectContainer 子类作为该类的基类: • 如果关联的影片剪辑元件在多个帧上有内容,请选择 MovieClip • 如果关联的影片剪辑元件仅在第一帧上有内容,请选择 Sprite 处理显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 无论选择使用哪个显示对象,都会有许多的操作,这些操作作为屏幕上显示的一些元素是所有显示对象共有的。例如,可以在 屏幕上确定所有显示对象的位置、前后移动显示对象的堆叠顺序、缩放或旋转显示对象等。因为所有显示对象都从它们共有的 基类 (DisplayObject) 继承了此功能,所以无论是要操作 TextField 实例、Video 实例、Shape 实例还是其他任何显示对象, 此功能的行为都相同。以下部分将详细说明几个常用显示对象操作。 改变位置 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 对任何显示对象进行的最基本操作是确定显示对象在屏幕上的位置。若要设置显示对象的位置,请更改对象的 x 和 y 属性。 myShape.x = 17; myShape.y = 212; 显示对象定位系统将舞台视为一个笛卡尔坐标系 (带有水平 x 轴和垂直 y 轴的常见网格系统)。坐标系的原点(x 和 y 轴相交 的 0,0 坐标)位于舞台的左上角。从原点开始, x 轴的值向右为正,向左为负,而 y 轴的值向下为正,向上为负 (与典型的图 形系统相反)。例如,通过前面的代码行可以将对象 myShape 移到 x 轴坐标 17(原点向右 17 个像素)和 y 轴坐标 212(原点 向下 212 个像素)。 默认情况下,当使用 ActionScript 创建显示对象时, x 和 y 属性均设置为 0,从而可将对象放在其父内容的左上角。 改变相对于舞台的位置 x 和 y 属性始终是指显示对象相对于其父显示对象坐标轴的 0,0 坐标的位置,记住这一点很重要。因此,对于包含在 Sprite 实 例内的 Shape 实例(如圆),如果将 Shape 对象的 x 和 y 属性设置为 0,则会将圆放在 Sprite 的左上角,该位置不一定是舞台 的左上角。若要确定对象相对于全局舞台坐标的位置,可以使用任何显示对象的 globalToLocal() 方法将坐标从全局 (舞台)坐 标转换为本地 (显示对象容器)坐标,如下所示:145ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 // Position the shape at the top-left corner of the Stage, // regardless of where its parent is located. // Create a Sprite, positioned at x:200 and y:200. var mySprite:Sprite = new Sprite(); mySprite.x = 200; mySprite.y = 200; this.addChild(mySprite); // Draw a dot at the Sprite's 0,0 coordinate, for reference. mySprite.graphics.lineStyle(1, 0x000000); mySprite.graphics.beginFill(0x000000); mySprite.graphics.moveTo(0, 0); mySprite.graphics.lineTo(1, 0); mySprite.graphics.lineTo(1, 1); mySprite.graphics.lineTo(0, 1); mySprite.graphics.endFill(); // Create the circle Shape instance. var circle:Shape = new Shape(); mySprite.addChild(circle); // Draw a circle with radius 50 and center point at x:50, y:50 in the Shape. circle.graphics.lineStyle(1, 0x000000); circle.graphics.beginFill(0xff0000); circle.graphics.drawCircle(50, 50, 50); circle.graphics.endFill(); // Move the Shape so its top-left corner is at the Stage's 0, 0 coordinate. var stagePoint:Point = new Point(0, 0); var targetPoint:Point = mySprite.globalToLocal(stagePoint); circle.x = targetPoint.x; circle.y = targetPoint.y; 同样,也可以使用 DisplayObject 类的 localToGlobal() 方法将本地坐标转换为舞台坐标。 使用鼠标移动显示对象 您可以在 ActionScript 中使用两种技术使用户可以使用鼠标来移动显示对象。在这两种情况下,会使用两个鼠标事件:按下 鼠标按键时,通知对象跟随鼠标光标;松开鼠标按键时,通知对象停止跟随鼠标光标。 注: Flash Player 11.3 及更高版本,AIR 3.3 及更高版本:您也可以使用 MouseEvent.RELEASE_OUTSIDE 事件涵盖用户 在包含 Sprite 的边界外释放鼠标按钮的情况。 第一种技术使用 startDrag() 方法,比较简单,但限制较多。按下鼠标按键时,将调用要拖动的显示对象的 startDrag() 方法。松 开鼠标按键时,将调用 stopDrag() 方法。 Sprite 类定义这两个功能,因此移动的对象必须是 Sprite 或它的子类。146ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 // This code creates a mouse drag interaction using the startDrag() // technique. // square is a MovieClip or Sprite instance). import flash.events.MouseEvent; // This function is called when the mouse button is pressed. function startDragging(event:MouseEvent):void { square.startDrag(); } // This function is called when the mouse button is released. function stopDragging(event:MouseEvent):void { square.stopDrag(); } square.addEventListener(MouseEvent.MOUSE_DOWN, startDragging); square.addEventListener(MouseEvent.MOUSE_UP, stopDragging); 这种方法有一个非常大的限制:使用 startDrag() 时,每次只能拖动一个项目。如果正在拖动一个显示对象,然后对另一个显示 对象调用了 startDrag() 方法,则第一个显示对象会立即停止跟随鼠标。例如,如果 startDragging() 函数如下发生了更改,则只 拖动 circle 对象,而不管 square.startDrag() 方法调用: function startDragging(event:MouseEvent):void { square.startDrag(); circle.startDrag(); } 由于每次只能使用 startDrag() 拖动一个对象,因此,可以对任何显示对象调用 stopDrag() 方法,这会停止当前正在拖动的任何 对象。 如果需要拖动多个显示对象,或者为了避免因多个对象可能使用 startDrag() 而发生冲突,最好使用鼠标跟随方法来创建拖动效 果。通过这种技术,当按下鼠标按键时,会将函数作为舞台的 mouseMove 事件的侦听器来订阅。然后,每次鼠标移动时都会 调用此函数,它将使所拖动的对象跳到鼠标所在的 x,y 坐标。松开鼠标按键后,取消此函数作为侦听器的订阅,这意味着鼠标 移动时不再调用该函数且对象停止跟随鼠标光标。下面是演示说明此技术的一些代码: // This code moves display objects using the mouse-following // technique. // circle is a DisplayObject (e.g. a MovieClip or Sprite instance). import flash.events.MouseEvent; var offsetX:Number; var offsetY:Number; // This function is called when the mouse button is pressed. function startDragging(event:MouseEvent):void { // Record the difference (offset) between where // the cursor was when the mouse button was pressed and the x, y // coordinate of the circle when the mouse button was pressed. offsetX = event.stageX - circle.x; offsetY = event.stageY - circle.y; // tell Flash Player to start listening for the mouseMove event stage.addEventListener(MouseEvent.MOUSE_MOVE, dragCircle); } // This function is called when the mouse button is released. 147ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 function stopDragging(event:MouseEvent):void { // Tell Flash Player to stop listening for the mouseMove event. stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragCircle); } // This function is called every time the mouse moves, // as long as the mouse button is pressed down. function dragCircle(event:MouseEvent):void { // Move the circle to the location of the cursor, maintaining // the offset between the cursor's location and the // location of the dragged object. circle.x = event.stageX - offsetX; circle.y = event.stageY - offsetY; // Instruct Flash Player to refresh the screen after this event. event.updateAfterEvent(); } circle.addEventListener(MouseEvent.MOUSE_DOWN, startDragging); circle.addEventListener(MouseEvent.MOUSE_UP, stopDragging); 除使显示对象跟随鼠标光标之外,经常需要将拖动的对象移动到显示的前方,以使其像是浮动在所有其他对象上。例如,假设 您有两个对象 (一个圆和一个正方形),都可以跟随鼠标移动。如果圆在显示列表中出现在正方形之下,您单击并拖动圆时光 标会出现在正方形之上,圆好像在正方形之后滑动,这样中断了拖放视觉效果。您可以使用拖放交互组件避免这一点,以便在 单击圆时圆移到显示列表的顶部,使圆会始终出现在其他任何内容的顶部。 以下代码 (根据上一示例改写)使两个显示对象 (一个圆和一个正方形)可跟随鼠标移动。只要在任一个显示对象上按下鼠标 按键,该显示对象就会移到舞台显示列表的顶部,所以拖动的项目始终出现在顶部。(新代码或根据以前代码更改的代码显示 为粗体。) // This code creates a drag-and-drop interaction using the mouse-following // technique. // circle and square are DisplayObjects (e.g. MovieClip or Sprite // instances). import flash.display.DisplayObject; import flash.events.MouseEvent; var offsetX:Number; var offsetY:Number; var draggedObject:DisplayObject; // This function is called when the mouse button is pressed. function startDragging(event:MouseEvent):void { // remember which object is being dragged draggedObject = DisplayObject(event.target); // Record the difference (offset) between where the cursor was when // the mouse button was pressed and the x, y coordinate of the // dragged object when the mouse button was pressed. offsetX = event.stageX - draggedObject.x; offsetY = event.stageY - draggedObject.y; // move the selected object to the top of the display list stage.addChild(draggedObject); // Tell Flash Player to start listening for the mouseMove event. stage.addEventListener(MouseEvent.MOUSE_MOVE, dragObject); } 148ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 // This function is called when the mouse button is released. function stopDragging(event:MouseEvent):void { // Tell Flash Player to stop listening for the mouseMove event. stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragObject); } // This function is called every time the mouse moves, // as long as the mouse button is pressed down. function dragObject(event:MouseEvent):void { // Move the dragged object to the location of the cursor, maintaining // the offset between the cursor's location and the location // of the dragged object. draggedObject.x = event.stageX - offsetX; draggedObject.y = event.stageY - offsetY; // Instruct Flash Player to refresh the screen after this event. event.updateAfterEvent(); } circle.addEventListener(MouseEvent.MOUSE_DOWN, startDragging); circle.addEventListener(MouseEvent.MOUSE_UP, stopDragging); square.addEventListener(MouseEvent.MOUSE_DOWN, startDragging); square.addEventListener(MouseEvent.MOUSE_UP, stopDragging); 若要进一步扩展这种效果,如在几副纸牌 (或几组标记)之间移动纸牌 (或标记)的游戏中,您可以在 “ 拿出 ” 拖动对象时将 拖动对象添加到舞台的显示列表中,然后在 “ 放入 ” 拖动对象时 (通过松开鼠标按键)将拖动对象添加到另一个显示列表中 (如 “ 那副纸牌 ” 或 “ 那组标记 ”)。 最后,要增强效果,您可以在单击显示对象时 (开始拖动显示对象时)对显示对象应用投影滤镜,然后在松开对象时删除投 影。有关在 ActionScript 中使用投影滤镜和其他显示对象滤镜的详细信息,请参阅第 224 页的 “ 过滤显示对象 ”。 平移和滚动显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如果显示对象太大,不能在要显示它的区域中完全显示出来,则可以使用 scrollRect 属性定义显示对象的可查看区域。此外, 通过更改 scrollRect 属性响应用户输入,可以使内容左右平移或上下滚动。 scrollRect 属性是 Rectangle 类的实例,Rectangle 类包括将矩形区域定义为单个对象所需的有关值。最初定义显示对象的可查 看区域时,请创建一个新的 Rectangle 实例并为该实例分配显示对象的 scrollRect 属性。以后进行滚动或平移时,请将 scrollRect 属性读入单独的 Rectangle 变量,然后更改所需的属性 (例如,更改 Rectangle 实例的 x 属性进行平移,或更改 y 属性进行滚动)。然后将该 Rectangle 实例重新分配给 scrollRect 属性,将更改的值通知显示对象。 例如,下面的代码定义名为 bigText 的 TextField 对象的可查看区域,该对象因太高而无法容纳在 SWF 文件的边界内。单击名 为 up 和 down 的两个按钮时,它们调用的函数通过修改 scrollRect Rectangle 实例的 y 属性而使 TextField 对象的内容向上或 向下滚动。149ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 import flash.events.MouseEvent; import flash.geom.Rectangle; // Define the initial viewable area of the TextField instance: // left: 0, top: 0, width: TextField's width, height: 350 pixels. bigText.scrollRect = new Rectangle(0, 0, bigText.width, 350); // Cache the TextField as a bitmap to improve performance. bigText.cacheAsBitmap = true; // called when the "up" button is clicked function scrollUp(event:MouseEvent):void { // Get access to the current scroll rectangle. var rect:Rectangle = bigText.scrollRect; // Decrease the y value of the rectangle by 20, effectively // shifting the rectangle down by 20 pixels. rect.y -= 20; // Reassign the rectangle to the TextField to "apply" the change. bigText.scrollRect = rect; } // called when the "down" button is clicked function scrollDown(event:MouseEvent):void { // Get access to the current scroll rectangle. var rect:Rectangle = bigText.scrollRect; // Increase the y value of the rectangle by 20, effectively // shifting the rectangle up by 20 pixels. rect.y += 20; // Reassign the rectangle to the TextField to "apply" the change. bigText.scrollRect = rect; } up.addEventListener(MouseEvent.CLICK, scrollUp); down.addEventListener(MouseEvent.CLICK, scrollDown); 正如此示例所示,使用显示对象的 scrollRect 属性时,最好指定 Flash Player 或 AIR 应使用 cacheAsBitmap 属性将显示对象的 内容缓存为位图。这样,每次滚动显示对象时,Flash Player 和 AIR 就不必重绘显示对象的整个内容,而只需改用缓存的位图 即可将所需部分直接呈示到屏幕上。有关详细信息,请参阅第 152 页的 “ 缓存显示对象 ”。 处理大小和缩放对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 有两种方式可测量和操作显示对象的大小:使用尺寸属性 (width 和 height)或缩放属性 (scaleX 和 scaleY)。 每个显示对象都有 width 属性和 height 属性,它们最初设置为对象的大小,以像素为单位。您可以通过读取这些属性的值来确 定显示对象的大小。还可以指定新值来更改对象的大小,如下所示: // Resize a display object. square.width = 420; square.height = 420; // Determine the radius of a circle display object. var radius:Number = circle.width / 2;150ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 更改显示对象的 height 或 width 会导致缩放对象,这意味着对象内容将经过伸展或挤压以适合新区域的大小。如果显示对象仅 包含矢量形状,将按新缩放比例重绘这些形状,而品质不变。此时将缩放显示对象中的所有位图图形元素,而不是重绘。例 如,缩放图形时,如果数码照片的宽度和高度增加后超出图像中像素信息的实际大小,数码照片将被像素化,使数码照片显示 带有锯齿。 当更改显示对象的 width 或 height 属性时, Flash Player 和 AIR 也会更新对象的 scaleX 和 scaleY 属性。 注: TextField 对象是此缩放行为的例外。文本字段需要调整自身大小,以适应文本自动换行和字体大小,因此文本字段在调 整大小之后将其 scaleX 或 scaleY 值重置为 1。但是,如果调整 TextField 对象的 scaleX 或 scaleY 值,则宽度和高度值会更 改,以适应您提供的缩放值。 这些属性表示显示对象与其原始大小相比的相对大小。 scaleX 和 scaleY 属性使用小数 (十进制)值来表示百分比。例如,如果 某个显示对象的 width 已更改,其宽度是原始大小的一半,则该对象的 scaleX 属性的值为 .5,表示 50%。如果其高度加倍,则 其 scaleY 属性的值为 2,表示 200%。 // circle is a display object whose width and height are 150 pixels. // At original size, scaleX and scaleY are 1 (100%). trace(circle.scaleX); // output: 1 trace(circle.scaleY); // output: 1 // When you change the width and height properties, // Flash Player changes the scaleX and scaleY properties accordingly. circle.width = 100; circle.height = 75; trace(circle.scaleX); // output: 0.6622516556291391 trace(circle.scaleY); // output: 0.4966887417218543 此时,大小更改不成比例。换句话说,如果更改一个正方形的 height 但不更改其 width,则其边长不再相同,它将是一个矩形 而不是一个正方形。如果要更改显示对象的相对大小,则可以通过设置 scaleX 和 scaleY 属性的值来调整该对象的大小,另一种 方法是设置 width 或 height 属性。例如,下面的代码将更改名为 square 的显示对象的 width,然后更改垂直缩放 (scaleY) 以匹 配水平缩放,所以正方形的大小成比例。 // Change the width directly. square.width = 150; // Change the vertical scale to match the horizontal scale, // to keep the size proportional. square.scaleY = square.scaleX; 控制缩放时的扭曲 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 通常,缩放显示对象 (例如水平伸展)时,引起的扭曲在整个对象上是均匀分布的,所以各部分的伸展量是相同的。对于图形 和设计元素,这可能是您所希望的结果。但是,有时更希望能控制显示对象的某些部分伸展、某些部分保持不变。这种情况的 一个常见示例是有圆角的矩形按钮。进行正常缩放时,按钮的角将伸展,从而使角半径随按钮大小的调整而改变。151ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 但在这种情况下,最好对缩放进行控制,即能够指定应缩放的某些区域 (直边和中间)和不应缩放的区域 (角),以便在缩放 后不会出现可见的扭曲。 可以使用 9 切片缩放 (Scale-9) 来创建在其中控制如何缩放对象的显示对象。使用 9 切片缩放时,显示对象被分成 9 个单独的 矩形 (一个 3 x 3 的网格,就像一个 “ 井 ” 字)。矩形的大小不必一定相同,您可以指定放置网格线的位置。缩放显示对象时, 四个角矩形中的任何内容 (如按钮的圆角)不伸展也不压缩。上中矩形和下中矩形将进行水平缩放,但不进行垂直缩放,而左 中矩形和右中矩形将进行垂直缩放,但不进行水平缩放。中心矩形既进行水平缩放又进行垂直缩放。 请记住,如果要创建显示对象且希望某些内容从不缩放,只需要通过放置 9 切片缩放网格的划分线来确保有关内容完全放在其 中一个角矩形中即可。 在 ActionScript 中,如果为显示对象的 scale9Grid 属性设置一个值,就会打开该对象的 9 切片缩放并定义该对象的缩放 9 网格 中矩形的大小。可以使用 Rectangle 类的实例作为 scale9Grid 属性的值,如下所示: myButton.scale9Grid = new Rectangle(32, 27, 71, 64); Rectangle 构造函数的四个参数是 x 坐标、 y 坐标、 width 和 height。在此示例中,矩形的左上角放在名为 myButton 的显示 对象上的点 x: 32,y: 27 处。矩形宽 71 个像素,高 64 个像素(因此其右边位于显示对象上 x 坐标为 103 的位置,其下边位于 显示对象上 y 坐标为 92 的位置)。 包含在由 Rectangle 实例定义的区域中的实际区域表示 Scale-9 网格的中心矩形。其他矩形是由 Flash Player 和 AIR 通过扩 展 Rectangle 实例的各边计算出来的,如下所示: 在本例中,当按钮放大或缩小时,圆角不拉伸也不压缩,但其他区域将通过调整来适应缩放。 A. myButton.width = 131;myButton.height = 106; B. myButton.width = 73;myButton.height = 69; C. myButton.width = 54;myButton.height = 141; CBA152ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 缓存显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如果 Flash 中的设计尺寸增大,无论创建的是应用程序还是复杂的脚本动画,都需要考虑性能和优化。如果内容保持为静态 (如矩形 Shape 实例),则 Flash Player 和 AIR 不会优化内容。因此,更改矩形的位置时,Flash Player 或 AIR 会重绘整个 Shape 实例。 可以通过缓存指定的显示对象来提高 SWF 文件的性能。显示对象是一个 “ 表面 ”,实际上是位图版本的实例矢量数据,而矢量 数据是 SWF 文件中不需要进行太多更改的一种数据。因此,打开缓存的实例不会随 SWF 文件的播放而不断地重绘,这样便可 快速呈示 SWF 文件。 注: 可以更新矢量数据,这时将重新创建表面。因此,缓存在表面中的矢量数据不需要在整个 SWF 文件中保持一样。 将显示对象的 cacheAsBitmap 属性设置为 true 会使显示对象缓存其自身的位图表示形式。Flash Player 或 AIR 为该实例创建一 个表面对象,该对象是一个缓存的位图,而不是矢量数据。如果要更改显示对象的边框,则重新创建表面而不是调整其大小。 表面可以嵌套在其他表面之内。子表面会将其位图复制到它的父表面上。有关详细信息,请参阅第 153 页的 “ 启用位图缓存 ”。 DisplayObject 类的 opaqueBackground 属性和 scrollRect 属性与使用 cacheAsBitmap 属性的位图缓存有关。尽管这三个属性彼 此互相独立,但当对象缓存为位图时, opaqueBackground 和 scrollRect 属性的作用最佳;只有将 cacheAsBitmap 设置为 true 时,才能看到 opaqueBackground 和 scrollRect 属性带来的性能优势。有关滚动显示对象内容的详细信息,请参阅第 148 页的 “ 平移和滚动显示对象 ”。有关设置不透明背景的详细信息,请参阅第 154 页的 “ 设置不透明背景颜色 ”。 有关 Alpha 通道遮罩 (要求将 cacheAsBitmap 属性设置为 true)的信息,请参阅第 158 页的 “ 遮罩显示对象 ”。 何时启用缓存 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 对显示对象启用缓存可创建表面,表面具有助于更快地呈示复杂的矢量动画等优点。有几种情形需要启用缓存。可能您总是希 望通过启用缓存来提高 SWF 文件的性能;但是,某些情况下启用缓存并不能提高性能,甚至还会降低性能。本部分介绍在哪 些情况下应使用缓存,以及何时使用常规显示对象。 缓存数据的总体性能取决于实例的矢量数据的复杂程度、要更改的数据量,以及是否设置了 opaqueBackground 属性。如果要 更改的范围较小,则使用表面和使用矢量数据的差异微乎其微。在部署应用程序之前您可能需要实际测试一下这两种情况。 何时使用位图缓存 在以下典型情形中启用位图缓存您可能会看到明显的好处。 • 复杂背景图像:包含矢量数据的详细的复杂背景图像的应用程序 (可能是应用了跟踪位图命令的图像,也可能是在 Adobe Illustrator® 中创建的插图)。您可能会在背景上设计动画人物,这会降低动画的速度,因为背景需要持续地重新生成矢量 数据。要提高性能,可以将背景显示对象的 opaqueBackground 属性设置为 true。背景将呈示为位图,可以迅速地重新绘 制,以便更快地播放动画。 • 滚动文本字段:应用程序在滚动文本字段中显示大量的文本。可以将文本字段放置在您设置为可滚动的具有滚动框 (使用 scrollRect 属性)的显示对象中。这可以使指定的实例进行快速像素滚动。当用户滚动显示对象实例时, Flash Player 或 AIR 会通过将滚动的像素向上移来生成新的看得见的区域,而不是重新生成整个文本字段。 • 窗口排列秩序:应用程序具有秩序复杂的重叠窗口。每个窗口都可以打开或关闭 (例如, Web 浏览器窗口)。如果将每个 窗口标记为一个表面 (将 cacheAsBitmap 属性设置为 true),则各个窗口将隔离开来进行缓存。用户可以拖动窗口使其互相 重叠,每个窗口无需重新生成矢量内容。 • Alpha 通道遮罩:当使用 Alpha 通道遮罩时,必须将 cacheAsBitmap 属性设置为 true。有关详细信息,请参阅第 158 页的 “ 遮罩显示对象 ”。 所有这些情况下,启用位图缓存后都通过优化矢量图来提高应用程序的响应能力和互动性。153ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 此外,只要对显示对象应用滤镜, cacheAsBitmap 就会自动设置为 true,即使将其明确设置为 false 也是如此。如果清除了显示 对象的所有滤镜,则 cacheAsBitmap 属性会返回最后设置的值。 何时避免使用位图缓存 在错误的环境中使用此功能可能会给 SWF 文件带来负面影响。使用位图缓存时,请记住下面的准则: • 不要过度使用表面 (启用了缓存的显示对象)。每个表面使用的内存都比常规显示对象多,这意味着只在需要提高呈示性能 时才启用表面。 缓存的位图使用的内存比常规显示对象多很多。例如,如果舞台上 Sprite 实例的大小为 250 x 250 个像素,缓存它可能会 使用 250 KB 内存;如果它是常规 (未缓存的) Sprite 实例,则使用 1 KB 内存。 • 避免放大缓存的表面。如果过度使用位图缓存,尤其是在缩小内容时,将使用大量内存 (请参阅上一段落)。 • 将表面用于通常为静态 (非动画)的显示对象实例。可以拖放或移动实例,但实例的内容不能为动画或更改太多。(动画或 变化的内容更可能包含在包含动画的 MovieClip 实例或 Video 实例中。)例如,如果旋转或转换实例,实例将在表面和矢 量数据之间进行变化,这种情况难于处理,并会对 SWF 文件产生负面影响。 • 如果将表面与矢量数据混在一起,将增加 Flash Player 和 AIR(有时还包括计算机)的工作量。应尽量将表面归为一组 — 例如,创建窗口应用程序时。 • 请不要缓存图形更改频繁的对象。每一次缩放、倾斜、旋转显示对象,更改 alpha 或颜色转换,移动子显示对象,或使用 图形属性绘图时,位图缓存都会重绘。如果每一帧都发生这种情况,运行时必须将对象绘制为位图,然后将该位图复制到舞 台 — 与仅将未缓存对象绘制到舞台相比,这会导致额外的工作量。缓存和更新频率之间的性能权衡取决于显示对象的复杂 性和大小,并且只能通过测试具体内容来确定。 启用位图缓存 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 要为显示对象启用位图缓存,请将它的 cacheAsBitmap 属性设置为 true: mySprite.cacheAsBitmap = true; 将 cacheAsBitmap 属性设置为 true 后,您可能会注意到,显示对象的像素会自动与整个坐标对齐。测试 SWF 文件时,您还会 注意到,在复杂矢量图像上执行的任何动画的呈示速度都快得多。 即便是将 cacheAsBitmap 设置为 true,如果出现以下一种或多种情形,也将不创建表面 (缓存的位图): • 位图高度或宽度超过 2880 像素。 • 位图分配不成功 (由于内存不足而出现的错误)。 缓存的位图转换矩阵 Adobe AIR 2.0 和更高版本 (移动配置文件) 在用于移动设备的 AIR 应用程序中,应在每次设置 cacheAsBitmap 属性的同时设置 cacheAsBitmapMatrix 属性。设置此属性可 让您在不触发重新呈现的前提下,将更加丰富的转换应用到显示对象。 mySprite.cacheAsBitmap = true; mySprite.cacheAsBitmapMatrix = new Matrix(); 设置此矩阵属性后,可在不重新缓存对象的前提下,向显示对象应用以下额外转换: • 在不发生像素贴紧的前提下进行移动或平移 • 旋转 • 缩放 • 倾斜效果154ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 • 更改 alpha (0 至 100% 的透明度) 这些转换会直接应用到缓存的位图。 设置不透明背景颜色 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以为显示对象设置不透明背景。例如,如果 SWF 的背景中包含复杂的矢量图片,则可以将 opaqueBackground 属性设置为指 定的颜色 (通常与舞台颜色相同)。将颜色指定为一个数字(通常为十六进制的颜色值)。然后可将背景视作位图,这样有助 于优化性能。 当将 cacheAsBitmap 设置为 true 并将 opaqueBackground 属性设置为指定的颜色时,opaqueBackground 属性可以使内部位图不 透明而加快呈示速度。如果不将 cacheAsBitmap 设置为 true,opaqueBackground 属性将在显示对象的背景中添加一个不透明的 矢量正方形形状。不会自动创建位图。 下面的示例说明了如何设置显示对象的背景以优化性能。 myShape.cacheAsBitmap = true; myShape.opaqueBackground = 0xFF0000; 在本例中,将名为 myShape 的 Shape 的背景颜色设置为红色 (0xFF0000)。假定 Shape 实例在白色背景的舞台上包含一个绿色 三角形绘图,这将在 Shape 实例的边框 (完全包含 Shape 的矩形)内显示一个绿色三角形,且空白区域为红色。 当然,如果此代码用于纯红色背景的舞台,则更合理。在其他颜色的背景上,则改为指定该颜色。例如,在白色背景的 SWF 中, opaqueBackground 属性最适合设置为 0xFFFFFF 或纯白色。 应用混合模式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 混合模式涉及将一个图像 (基图像)的颜色与另一个图像 (混合图像)的颜色进行组合来生成第三个图像,所得的图像是实际 在屏幕上显示的图像。图像中的每个像素值都会被使用其他图像的对应像素值进行处理,以便在结果的同一位置生成一个像素 值。 每个显示对象都有 blendMode 属性,可以将其设置为下列混合模式之一。以下是在 BlendMode 类中定义的常量。此外,还可 以使用 String 值 (在括号中),这些值是常量的实际值。 • BlendMode.ADD ("add"):通常用于创建两个图像之间的动画变亮模糊效果。 • BlendMode.ALPHA ("alpha"):通常用于在背景上应用前景的透明度。(在 GPU 呈现下不支持。) • BlendMode.DARKEN ("darken"):通常用于重叠类型。(在 GPU 呈现下不支持。) • BlendMode.DIFFERENCE ("difference"):通常用于创建更多变动的颜色。 • BlendMode.ERASE ("erase"):通常用于使用前景 Alpha 剪掉 (擦除)背景的一部分。(在 GPU 呈现下不支持。) • BlendMode.HARDLIGHT ("hardlight"):通常用于创建阴影效果。(在 GPU 呈现下不支持。) • BlendMode.INVERT ("invert"):用于反转背景。 • BlendMode.LAYER ("layer"):用于强制为特定显示对象的预构成创建临时缓冲区。(在 GPU 呈现下不支持。)155ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 • BlendMode.LIGHTEN ("lighten"):通常用于重叠类型。(在 GPU 呈现下不支持。) • BlendMode.MULTIPLY ("multiply"):通常用于创建阴影和深度效果。 • BlendMode.NORMAL ("normal"):用于指定混合图像的像素值覆盖基本图像的像素值。 • BlendMode.OVERLAY ("overlay"):通常用于创建阴影效果。(在 GPU 呈现下不支持。) • BlendMode.SCREEN ("screen"):通常用于创建亮点和镜头眩光。 • BlendMode.SHADER ("shader"):用于指定用于创建自定义混合效果的 Pixel Bender 着色器。有关使用着色器的详细信息, 请参阅第 251 页的 “ 使用 Pixel Bender 着色器 ”。(在 GPU 呈现下不支持。) • BlendMode.SUBTRACT ("subtract"):通常用于创建两个图像之间的动画变暗模糊效果。 调整 DisplayObject 颜色 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 ColorTransform 类的方法 (flash.geom.ColorTransform) 来调整显示对象的颜色。每个显示对象都有 transform 属性 (它是 Transform 类的实例),还包含有关应用到显示对象的各种变形的信息(如旋转、缩放或位置的更改等)。除了 有关几何变形的信息之外, Transform 类还包括 colorTransform 属性,它是 ColorTransform 类的实例,并提供访问来对显 示对象进行颜色调整。要访问显示对象的颜色转换信息,可以使用如下代码: var colorInfo:ColorTransform = myDisplayObject.transform.colorTransform; 创建 ColorTransform 实例后,可以通过读取其属性值来查明已应用了哪些颜色转换,也可以通过设置这些值来更改显示对象 的颜色。要在进行任何更改后更新显示对象,必须将 ColorTransform 实例重新分配给 transform.colorTransform 属性。 var colorInfo:ColorTransform = myDisplayObject.transform.colorTransform; // Make some color transformations here. // Commit the change. myDisplayObject.transform.colorTransform = colorInfo; 使用代码设置颜色值 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ColorTransform 类的 color 属性可用于为显示对象分配具体的红、绿、蓝 (RGB) 颜色值。在下面的示例中,当用户单击名为 blueBtn 的按钮时,将使用 color 属性将名为 square 的显示对象的颜色更改为蓝色:156ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 // square is a display object on the Stage. // blueBtn, redBtn, greenBtn, and blackBtn are buttons on the Stage. import flash.events.MouseEvent; import flash.geom.ColorTransform; // Get access to the ColorTransform instance associated with square. var colorInfo:ColorTransform = square.transform.colorTransform; // This function is called when blueBtn is clicked. function makeBlue(event:MouseEvent):void { // Set the color of the ColorTransform object. colorInfo.color = 0x003399; // apply the change to the display object square.transform.colorTransform = colorInfo; } blueBtn.addEventListener(MouseEvent.CLICK, makeBlue); 请注意,使用 color 属性更改显示对象的颜色时,将会完全更改整个对象的颜色,无论该对象以前是否有多种颜色。例如,如 果某个显示对象包含一个顶部有黑色文本的绿色圆,将该对象的关联 ColorTransform 实例的 color 属性设置为红色阴影时, 会使整个对象 (圆和文本)变为红色 (因此无法再将文本与该对象的其余部分区分开来)。 使用代码更改颜色和亮度效果 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 假设显示对象有多种颜色 (例如,数码照片),但是您不想完全重新调整对象的颜色,只想根据现有颜色来调整显示对象的颜 色。这种情况下, ColorTransform 类包括一组可用于进行此类调整的乘数属性和偏移属性。乘数属性的名分别为 redMultiplier、 greenMultiplier、 blueMultiplier 和 alphaMultiplier,它们的作用像彩色照片滤镜 (或彩色太阳镜)一样,可以 增强或削弱显示对象上的某些颜色。偏移属性 (redOffset、 greenOffset、 blueOffset 和 alphaOffset)可用于额外增加对象上某 种颜色的值,或用于指定特定颜色可以具有的最小值。 在 “ 属性 ” 检查器上的 “ 颜色 ” 弹出菜单中选择 “ 高级 ” 时,这些乘数和偏移属性与 Flash 创作工具中影片剪辑元件可用的高 级颜色设置相同。 下面的代码加载一个 JPEG 图像并为其应用颜色转换,当鼠标指针沿 x 轴和 y 轴移动时,将调整红色和绿色通道值。在本例 中,因为未指定偏移值,所以屏幕上显示的每个颜色通道的颜色值将表示图像中原始颜色值的一个百分比,这意味着任何给定 像素上显示的大部分红色或绿色都是该像素上红色或绿色的原始效果。157ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 import flash.display.Loader; import flash.events.MouseEvent; import flash.geom.Transform; import flash.geom.ColorTransform; import flash.net.URLRequest; // Load an image onto the Stage. var loader:Loader = new Loader(); var url:URLRequest = new URLRequest("http://www.helpexamples.com/flash/images/image1.jpg"); loader.load(url); this.addChild(loader); // This function is called when the mouse moves over the loaded image. function adjustColor(event:MouseEvent):void { // Access the ColorTransform object for the Loader (containing the image) var colorTransformer:ColorTransform = loader.transform.colorTransform; // Set the red and green multipliers according to the mouse position. // The red value ranges from 0% (no red) when the cursor is at the left // to 100% red (normal image appearance) when the cursor is at the right. // The same applies to the green channel, except it's controlled by the // position of the mouse in the y axis. colorTransformer.redMultiplier = (loader.mouseX / loader.width) * 1; colorTransformer.greenMultiplier = (loader.mouseY / loader.height) * 1; // Apply the changes to the display object. loader.transform.colorTransform = colorTransformer; } loader.addEventListener(MouseEvent.MOUSE_MOVE, adjustColor); 旋转对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用 rotation 属性可以旋转显示对象。可以通过读取此值来了解是否旋转了某个对象,如果要旋转该对象,可以将此属性设置 为一个数字 (以度为单位),表示要应用于该对象的旋转量。例如,下面的代码行将名为 square 的对象旋转 45 度 (一整周旋 转的 1/8): square.rotation = 45; 或者,也可以使用转换矩阵来旋转显示对象,第 175 页的 “ 使用几何结构 ” 中对此进行了介绍。 淡化对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以通过控制显示对象的透明度来使显示对象部分透明 (或完全透明),也可以通过更改透明度来使对象淡入或淡出。 DisplayObject 类的 alpha 属性用于定义显示对象的透明度(更确切地说是不透明度)。可以将 alpha 属性设置为介于 0 和 1 之 间的任何值,其中 0 表示完全透明, 1 表示完全不透明。例如,当使用鼠标单击名为 myBall 的对象时,下面的代码行将使该对 象变得部分 (50%) 透明: function fadeBall(event:MouseEvent):void { myBall.alpha = .5; } myBall.addEventListener(MouseEvent.CLICK, fadeBall);158ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 还可以使用通过 ColorTransform 类提供的颜色调整来更改显示对象的透明度。有关详细信息,请参阅第 155 页的 “ 调整 DisplayObject 颜色 ”。 遮罩显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以通过将一个显示对象用作遮罩来创建一个孔洞,透过该孔洞使另一个显示对象的内容可见。 定义遮罩 若要指示一个显示对象将是另一个显示对象的遮罩,请将遮罩对象设置为被遮罩的显示对象的 mask 属性: // Make the object maskSprite be a mask for the object mySprite. mySprite.mask = maskSprite; 被遮罩的显示对象显示在用作遮罩的显示对象的全部不透明区域之内。例如,下面的代码将创建一个包含 100 x 100 个像素的 红色正方形的 Shape 实例和一个包含半径为 25 个像素的蓝色圆的 Sprite 实例。单击圆时,它被设置为正方形的遮罩,所以显 示的正方形部分只是由圆完整部分覆盖的那一部分。换句话说,只有红色圆可见。 // This code assumes it's being run within a display object container // such as a MovieClip or Sprite instance. import flash.display.Shape; // Draw a square and add it to the display list. var square:Shape = new Shape(); square.graphics.lineStyle(1, 0x000000); square.graphics.beginFill(0xff0000); square.graphics.drawRect(0, 0, 100, 100); square.graphics.endFill(); this.addChild(square); // Draw a circle and add it to the display list. var circle:Sprite = new Sprite(); circle.graphics.lineStyle(1, 0x000000); circle.graphics.beginFill(0x0000ff); circle.graphics.drawCircle(25, 25, 25); circle.graphics.endFill(); this.addChild(circle); function maskSquare(event:MouseEvent):void { square.mask = circle; circle.removeEventListener(MouseEvent.CLICK, maskSquare); } circle.addEventListener(MouseEvent.CLICK, maskSquare); 用作遮罩的显示对象可拖动、设置动画,并可动态调整大小,可以在单个遮罩内使用单独的形状。遮罩显示对象不一定需要添 加到显示列表中。但是,如果希望在缩放舞台时也缩放遮罩对象,或者如果希望支持用户与遮罩对象的交互 (如用户控制的拖 动和调整大小),则必须将遮罩对象添加到显示列表中。只要遮罩对象已添加到显示列表中,显示对象的实际 z 索引 (从前到 后的顺序)就无关紧要了。(除了显示为遮罩对象外,遮罩对象将不会出现在屏幕上。)如果遮罩对象是包含多个帧的一个 MovieClip 实例,则遮罩对象会沿其时间轴播放所有帧,如果没有用作遮罩对象,也会出现同样的情况。通过将 mask 属性设 置为 null 可以删除遮罩: // remove the mask from mySprite mySprite.mask = null;159ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 不能使用一个遮罩对象来遮罩另一个遮罩对象。不能设置遮罩显示对象的 alpha 属性。只有填充可用于作为遮罩的显示对象中 ;笔触都会被忽略。 AIR 2 如果通过设置 cacheAsBitmap 和 cacheAsBitmapMatrix 属性来缓存被遮罩显示对象,则遮罩必须是被遮罩显示对象的子级。类 似地,如果被遮罩显示对象是被缓存的显示对象容器的子项,则遮罩和显示对象都必须是该容器的子项。如果被遮罩对象是多 个缓存显示对象容器的子项,则遮罩必须是距离显示列表中被遮罩对象最近的缓存容器的子项。 关于遮蔽设备字体 您可以使用显示对象遮罩用设备字体设置的文本。当使用显示对象遮罩用设备字体设置的文本时,遮罩的矩形边框会用作遮罩 形状。也就是说,如果为设备字体文本创建了非矩形的显示对象遮罩,则 SWF 文件中显示的遮罩将是遮罩的矩形边框的形状, 而不是遮罩本身的形状。 Alpha 通道遮罩 如果遮罩显示对象和被遮罩的显示对象都使用位图缓存,则支持 Alpha 通道遮罩,如下所示: // maskShape is a Shape instance which includes a gradient fill. mySprite.cacheAsBitmap = true; maskShape.cacheAsBitmap = true; mySprite.mask = maskShape; 例如, Alpha 通道遮罩的一个应用是对遮罩对象使用应用于被遮罩显示对象之外的滤镜。 在下面的示例中,将一个外部图像文件加载到舞台上。该图像 (更确切地说,是加载图像的 Loader 实例)将是被遮罩的显示 对象。渐变椭圆 (中心为纯黑色,边缘淡变为透明)绘制在图像上;这就是 Alpha 遮罩。两个显示对象都打开了位图缓存。 椭圆设置为图像的遮罩,然后使其可拖动。 // This code assumes it's being run within a display object container // such as a MovieClip or Sprite instance. import flash.display.GradientType; import flash.display.Loader; import flash.display.Sprite; import flash.geom.Matrix; import flash.net.URLRequest; // Load an image and add it to the display list. var loader:Loader = new Loader(); var url:URLRequest = new URLRequest("http://www.helpexamples.com/flash/images/image1.jpg"); loader.load(url); this.addChild(loader); // Create a Sprite. var oval:Sprite = new Sprite(); // Draw a gradient oval. var colors:Array = [0x000000, 0x000000]; var alphas:Array = [1, 0]; var ratios:Array = [0, 255]; 160ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 var matrix:Matrix = new Matrix(); matrix.createGradientBox(200, 100, 0, -100, -50); oval.graphics.beginGradientFill(GradientType.RADIAL, colors, alphas, ratios, matrix); oval.graphics.drawEllipse(-100, -50, 200, 100); oval.graphics.endFill(); // add the Sprite to the display list this.addChild(oval); // Set cacheAsBitmap = true for both display objects. loader.cacheAsBitmap = true; oval.cacheAsBitmap = true; // Set the oval as the mask for the loader (and its child, the loaded image) loader.mask = oval; // Make the oval draggable. oval.startDrag(true); 对象动画 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 动画是使内容移动或者使内容随时间发生变化的过程。脚本动画是视频游戏的基础部分,通常用于将优美、有用的交互线索添 加到其他应用程序中。 脚本动画的基本概念是变化一定要发生,而且变化一定要分时间逐步完成。使用常见的循环语句,可以很容易地在 ActionScript 中使内容重复。但是,在更新显示之前,循环将遍历其所有迭代。要创建脚本动画,需要编写 ActionScript, 它随时间重复执行某个动作,每次运行时还更新屏幕。 例如,假设要创建一个简单的动画,如使球沿着屏幕运动。 ActionScript 提供了一个用于跟踪时间和相应更新屏幕的简单机 制,这意味着您可以编写代码,使球每次移动一点点,直到球到达目标为止。每次移动后,屏幕都会更新,从而使跨舞台的运 动在查看器中可见。 从实用的观点来看,让脚本动画与 SWF 文件的帧速率同步 (换句话说,每次显示或要显示新帧时都产生一个动画变化)才有 意义,因为帧速率定义了 Flash Player 或 AIR 更新屏幕的频率。每个显示对象都有 enterFrame 事件,它根据 SWF 文件的帧速 率来调度,即每帧一个事件。创建脚本动画的大多数开发人员都使用 enterFrame 事件作为一种方法来创建随时间重复的动作。 可以编写代码以侦听 enterFrame 事件,每一帧都让动画球移动一定的量,当屏幕更新时 (每一帧),将会在新位置重新绘制该 球,从而产生了运动。 注: 另一种随时间重复执行某个动作的方法是使用 Timer 类。每次过了指定的时间时,Timer 实例都会触发事件通知。可以编 写通过处理 Timer 类的 timer 事件来执行动画的代码,将时间间隔设置为一个很小的值 (几分之几秒)。有关使用 Timer 类 的详细信息,请参阅第 3 页的 “ 控制时间间隔 ”。 在下面的示例中,将在舞台上创建一个名为 circle 的圆 Sprite 实例。当用户单击圆时,脚本动画序列开始,从而使 circle 淡化 (其 alpha 属性值减少),直到完全透明:161ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; // draw a circle and add it to the display list var circle:Sprite = new Sprite(); circle.graphics.beginFill(0x990000); circle.graphics.drawCircle(50, 50, 50); circle.graphics.endFill(); addChild(circle); // When this animation starts, this function is called every frame. // The change made by this function (updated to the screen every // frame) is what causes the animation to occur. function fadeCircle(event:Event):void { circle.alpha -= .05; if (circle.alpha <= 0) { circle.removeEventListener(Event.ENTER_FRAME, fadeCircle); } } function startAnimation(event:MouseEvent):void { circle.addEventListener(Event.ENTER_FRAME, fadeCircle); } circle.addEventListener(MouseEvent.CLICK, startAnimation); 当用户单击圆时,将函数 fadeCircle() 订阅为 enterFrame 事件的侦听器,这意味着每一帧都会开始调用一次该函数。通过更改 circle 的 alpha 属性,该函数会淡化圆,因此对于每个帧,圆的 alpha 都会减少 .05 (5%) 并会更新屏幕。最后,当 alpha 值为 0 (circle 完全透明)时, fadeCircle() 函数作为事件侦听器将被删除,从而结束动画。 以上代码还可用来创建动画运动而不是淡化。通过用不同属性替换函数中表示 enterFrame 事件侦听器的 alpha,就可获得该属 性的动画效果。例如,将以下行 circle.alpha -= .05; 更改为以下代码 circle.x += 5; 将获得 x 属性的动画效果,使圆移到舞台的右侧。当到达需要的 x 坐标时,通过更改结束动画的条件就可结束动画 (即取消订 阅 enterFrame 侦听器)。 舞台方向 AIR 2.0 和更高版本 移动设备通常会重新定向用户界面,以便在用户旋转设备时保持垂直显示。如果您在应用程序中启用了自动方向,则设备会自 动保持适当的显示方向,但您需要自行确保舞台的高宽比发生更改后,内容的显示效果仍可接受。如果禁用自动方向,则除非 您手动更改显示方向,否则设备的显示方向将保持不变。 AIR 应用程序可在各种不同的移动设备和操作系统中运行。不同操作系统,甚至不同设备上的同一操作系统的基本方向行为可 能有所不同。一种适用于所有设备和操作系统的简单设计策略是启用自动方向并侦听 Stage 对象的 resize 事件,以确定何时需 要刷新应用程序布局。 162ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 或者,如果您的应用程序仅支持纵向高宽比或仅支持横向高宽比,可以禁用自动方向,并在 AIR 应用程序描述符中设置支持的 高宽比。此设计策略可提供一致的行为并可针对所选高宽比选择 “ 最佳的 ” 方向。例如,如果指定横向高宽比,则选择的方向 适合使用横向模式滑出键盘的设备。 获取当前舞台方向和高宽比 所报告的方向是相对于设备的正常位置而言。大多数设备都具有明确的垂直位置。该位置将被视为默认 方向。其他可能的方向 分别为:向左旋转、向右旋转 和向下翻转。 StageOrientation 类定义在设置或比较方向值时使用的字符串常量。 Stage 类定义两个用于报告方向的属性: • Stage.deviceOrientation — 报告设备相对于默认位置的物理方向。 注: 在某些情况下, deviceOrientation 可能会不可用,例如应用程序初次启动或设备平放时。在这些情况下,设备方向将 报告为未知。 • Stage.orientation — 报告舞台相对于默认方向的方向。启用自动方向后,当设备保持垂直时,舞台将向相反方向旋转。因 此,orientation 属性报告的右和左的位置将与 deviceOrientation 属性报告的位置相反。例如,如果 deviceRotation 报告向右 旋转,则 orientation 将报告向左旋转。 舞台的高宽比可以通过简单的比较舞台当前的宽度和高度推导出来。 var aspect:String = this.stage.stageWidth >= this.stage.stageHeight ? StageAspectRatio.LANDSCAPE : StageAspectRatio.PORTRAIT; 自动方向 启用自动方向后,当用户旋转其设备时,操作系统会重新定向整个用户界面,包括系统任务栏和应用程序。因此,舞台的高宽 比将会从纵向变为横向,或者从横向变为纵向。高宽比发生更改时,舞台尺寸也会更改。 通过将 Stage 对象的 autoOrients 属性设置为 true 或 false,可在运行时启用或禁用自动方向。可以在 AIR 应用程序描述符中使 用 元素来设置此属性的初始值。(请注意,对于 AIR 2.6 之前的版本, autoOrients 是一个只读属性,并且只能 在应用程序描述符中设置。) 如果您指定一个横向或纵向的高宽比,同时启用了自动方向, AIR 将自动方向限制为指定的高宽比。 舞台尺寸更改 舞台尺寸发生更改时,舞台内容将按照 Stage 对象的 scaleMode 和 align 属性的指定进行缩放和重新定位。在大多数情况下,依 赖由 Stage 对象的 scaleMode 设置提供的自动行为不会产生理想的效果。您必须重新布局或重新绘制图形和组件以支持多种高 宽比。(提供灵活的布局逻辑也意味着您的应用程序可以更好地适应具有不同屏幕大小和高宽比的各种设备。) 下图演示了在旋转典型移动设备时,不同 scaleMode 设置的效果:163ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 从横向高宽比旋转到纵向高宽比 该图演示了从横向高宽比旋转到纵向高宽比时不同缩放模式发生的缩放行为。从纵向旋转到横向会引起一系列相似的效果。 方向更改事件 Stage 对象会调度两种类型的事件,您可以将其用于检测方向更改并做出响应。启用自动方向时,会调度舞台 resize 和 orientationChange 事件。 如果您依赖自动方向来保持垂直显示,则 resize 事件是您的最佳选择。当舞台调度 resize 事件时,您的内容会根据需要重新布 局或重新绘制。仅当舞台缩放模式设置为 noScale 时,才会调度 resize 事件。 orientationChange 事件也可以用于检测方向更改。仅当自动方向启用时,才会调度 orientationChange 事件。 注: 在某些移动平台上,舞台会在调度 resize 或 orientationChange 事件之前调度一个可取消的 orientationChanging 事件。 由于并非所有平台都支持该事件,因此请避免依赖该事件。 手动方向 AIR 2.6 和更高版本 可以使用舞台的 setOrientation() 或 setAspectRatio() 方法控制舞台方向。 设置舞台方向 可以使用 Stage 对象的 setOrientation() 方法在运行时设置舞台方向。使用 StageOrientation 类指定的字符串常量指定所需的 方向: this.stage.setOrientation( StageOrientation.ROTATED_RIGHT ); 并不是所有设备和操作系统都支持每个可能的方向。例如, Android 2.2 在纵向标准设备上不支持以编程方式选择向左旋转方 向,并且根本不支持向下翻转方向。舞台的 supportedOrientations 属性提供了一个可以传递到 setOrientation() 方法的方向列 表:164ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 var orientations:Vector. = this.stage.supportedOrientations; for each( var orientation:String in orientations ) { trace( orientation ); } 设置舞台高宽比 如果您非常在意舞台的高宽比,则可以将高宽比设置为纵向或横向。可以使用舞台的 setAspectRatio() 方法在 AIR 应用程序描 述符中或在运行时设置高宽比: this.stage.setAspectRatio( StageAspectRatio.LANDSCAPE ); 运行时为指定的高宽比选择两个可能的方向之一。这可能与当前设备的方向不匹配。例如,默认的方向选定为首选上下翻转方 向(AIR 3.2 及早期版本),适用于滑动式键盘的方向选定为首选反向。 (AIR 3.3 及更高版本)从 AIR 3.3(SWF 版本 16)开始,您也可以使用 StageAspectRatio.ANY 常数。如果 Stage.autoOrients 设置为 true,而且您调用了 setAspectRatio(StageAspectRatio.ANY),您的应用程序能够将方向重新调整为所有方向 (横向 - 左、横向 - 右、纵向以及纵向和上下翻转)。同样是 AIR 3.3 的新功能,高宽比保持不变,进一步旋转设备限制为指定方向。 示例:将舞台方向设置为与设备方向相匹配 下面的示例演示了更新舞台方向以匹配当前设备方向的功能。舞台的 deviceOrientation 属性指示设备的物理方向,即使关闭了 自动方向也会指示。 function refreshOrientation( theStage:Stage ):void { switch ( theStage.deviceOrientation ) { case StageOrientation.DEFAULT: theStage.setOrientation( StageOrientation.DEFAULT ); break; case StageOrientation.ROTATED_RIGHT: theStage.setOrientation( StageOrientation.ROTATED_LEFT ); break; case StageOrientation.ROTATED_LEFT: theStage.setOrientation( StageOrientation.ROTATED_RIGHT ); break; case StageOrientation.UPSIDE_DOWN: theStage.setOrientation( StageOrientation.UPSIDE_DOWN ); break; default: //No change } } 方向更改是异步执行的。可以侦听舞台调度的 orientationChange 事件以检测更改的完成情况。如果某个设备不支持某个方向, setOrientation() 调用将失败且不引发错误。 动态加载显示内容 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以将下列任何外部显示资源加载到 ActionScript 3.0 应用程序中: • 在 ActionScript 3.0 中创作的 SWF 文件 — 此文件可以是 Sprite、MovieClip 或扩展 Sprite 的任何类。在 iOS 上的 AIR 应用程序中,只能加载不包含 ActionScript 字节代码的 SWF 文件。这意味着可以加载包含嵌入数据 (如图像和声音)的 SWF 文件,但不能加载包含可执行代码的 SWF 文件。165ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 • 图像文件 — 包括 JPG、 PNG 和 GIF 文件。 • AVM1 SWF 文件 — 用 ActionScript 1.0 或 2.0 编写的 SWF 文件。(在移动 AIR 应用程序中不受支持) 使用 Loader 类可以加载这些资源。 加载显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Loader 对象用于将 SWF 文件和图形文件加载到应用程序中。 Loader 类是 DisplayObjectContainer 类的子类。 Loader 对 象在其显示列表中只能包含一个子显示对象,该显示对象表示它加载的 SWF 或图形文件。如下面的代码所示,在显示列表中 添加 Loader 对象时,还可以在加载后将加载的子显示对象添加到显示列表中: var pictLdr:Loader = new Loader(); var pictURL:String = "banana.jpg" var pictURLReq:URLRequest = new URLRequest(pictURL); pictLdr.load(pictURLReq); this.addChild(pictLdr); 加载 SWF 文件或图像后,即可将加载的显示对象移到另一个显示对象容器中,如本示例中的 container DisplayObjectContainer 对象: import flash.display.*; import flash.net.URLRequest; import flash.events.Event; var container:Sprite = new Sprite(); addChild(container); var pictLdr:Loader = new Loader(); var pictURL:String = "banana.jpg" var pictURLReq:URLRequest = new URLRequest(pictURL); pictLdr.load(pictURLReq); pictLdr.contentLoaderInfo.addEventListener(Event.COMPLETE, imgLoaded); function imgLoaded(event:Event):void { container.addChild(pictLdr.content); } 监视加载进度 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 文件开始加载后,就创建了 LoaderInfo 对象。 LoaderInfo 对象用于提供加载进度、加载者和被加载者的 URL、媒体的字节 总数及媒体的标称高度和宽度等信息。 LoaderInfo 对象还调度用于监视加载进度的事件。166ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 下图说明 LoaderInfo 对象的不同用途 — 用于 SWF 文件的主类的实例、用于 Loader 对象以及用于由 Loader 对象加载的对 象: 可以将 LoaderInfo 对象作为 Loader 对象和加载的显示对象的属性进行访问。加载一开始,就可以通过 Loader 对象的 contentLoaderInfo 属性访问 LoaderInfo 对象。加载完显示对象后,也可以通过显示对象的 loaderInfo 属性,将 LoaderInfo 对象作为已加载显示对象的属性进行访问。已加载显示对象的 loaderInfo 属性是指与 Loader 对象的 contentLoaderInfo 属性相 同的 LoaderInfo 对象。换句话说,LoaderInfo 对象是加载的对象与加载它的 Loader 对象之间(加载者和被加载者之间)的 共享对象。 要访问加载的内容的属性,需要在 LoaderInfo 对象中添加事件侦听器,如下面的代码所示: import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; var ldr:Loader = new Loader(); var urlReq:URLRequest = new URLRequest("Circle.swf"); ldr.load(urlReq); ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded); addChild(ldr); function loaded(event:Event):void { var content:Sprite = event.target.content; content.scaleX = 2; } 有关详细信息,请参阅第 106 页的 “ 处理事件 ”。 指定加载上下文 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 通过 Loader 类的 load() 或 loadBytes() 方法将外部文件加载到 Flash Player 或 AIR 中时,可以选择指定 context 参数。此参数 是一个 LoaderContext 对象。 LoaderContext 类包括三个属性,用于定义如何使用加载的内容的上下文: • checkPolicyFile:仅当加载图像文件 (不是 SWF 文件)时才会使用此属性。如果将此属性设置为 true, Loader 将检查策 略文件的原始服务器 (请参阅第 901 页的 “ 网站控制 (策略文件) ”)。只有内容的来源域不是包含 Loader 对象的 SWF 舞台 SWF 文件 主类实例 Loader 对象 LoaderInfo 对象 内容 contentLoaderInfo 属性 loaderInfo 属性 LoaderInfo 对象 loaderInfo 属性167ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 文件所在的域时才需要此属性。如果服务器授予 Loader 域权限,Loader 域中 SWF 文件的 ActionScript 就可以访问加载 图像中的数据;换句话说,可以使用 BitmapData.draw() 命令访问加载的图像中的数据。 请注意,来自 Loader 对象所在域以外的其他域的 SWF 文件可以通过调用 Security.allowDomain() 来允许特定的域。 • securityDomain:仅当加载 SWF 文件 (不是图像)时才会使用此属性。如果 SWF 文件所在的域与包含 Loader 对象的文 件所在的域不同,则指定此属性。指定此选项时,Flash Player 将检查策略文件是否存在,如果存在,来自跨策略文件中允 许的域的 SWF 文件可以对加载的 SWF 内容执行跨脚本操作。可以将 flash.system.SecurityDomain.currentDomain 指定为此 参数。 • applicationDomain:仅当加载使用 ActionScript 3.0 编写的 SWF 文件(不是图像或使用 ActionScript 1.0 或 2.0 编写的 SWF 文件)时才会使用此属性。加载文件时,通过将 applicationDomain 参数设置为 flash.system.ApplicationDomain.currentDomain,可以指定将该文件包括在与 Loader 对象相同的应用程序域中。通过将加 载的 SWF 文件放在同一个应用程序域中,可以直接访问它的类。如果要加载的 SWF 文件中包含嵌入的媒体,这会很有帮 助,您可以通过其关联的类名访问嵌入的媒体。有关详细信息,请参阅第 123 页的 “ 使用应用程序域 ”。 下面的示例在从另一个域加载位图时检查策略文件: var context:LoaderContext = new LoaderContext(); context.checkPolicyFile = true; var urlReq:URLRequest = new URLRequest("http://www.[your_domain_here].com/photo11.jpg"); var ldr:Loader = new Loader(); ldr.load(urlReq, context); 下面的示例在从另一个域加载 SWF 时检查策略文件,以便将该文件与 Loader 对象放在同一个安全沙箱中。此外,该代码还 将加载的 SWF 文件中的类添加到与 Loader 对象的类相同的应用程序域中: var context:LoaderContext = new LoaderContext(); context.securityDomain = SecurityDomain.currentDomain; context.applicationDomain = ApplicationDomain.currentDomain; var urlReq:URLRequest = new URLRequest("http://www.[your_domain_here].com/library.swf"); var ldr:Loader = new Loader(); ldr.load(urlReq, context); 有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中的 LoaderContext 类。 在 AIR for iOS 中加载 SWF 文件 Adobe AIR 3.6 和更高版本,仅针对 iOS 在 iOS 设备上,对于在运行时加载和编译代码存在限制。由于这些限制,将外部 SWF 文件加载到您的应用程序中势必会有一 些不同: • 所有包含 ActionScript 代码的 SWF 文件都必须包括在应用程序包中。不能从外部源 (如通过网络)加载包含代码的 SWF。在对应用程序进行打包时,对于 iOS 设备,应用程序包中所有 SWF 文件中的所有 ActionScript 代码都将编译成本 机代码。 • 您不能加载 SWF 文件,然后卸载它再重新加载。如果这样做,会发生错误。 • 加载到内存中然后又卸载的行为与在桌面平台上这样操作的结果相同。如果加载 SWF 文件然后卸载它,包含在该 SWF 中 的所有可视资源都将从内存中卸载掉。不过,对所加载 SWF 中的 ActionScript 类的任何类引用将保留在内存中,可以在 ActionScript 代码中访问这些类引用。 • 加载的所有 SWF 文件必须与主 SWF 文件使用相同的应用程序域。这并非默认行为,因此对于每个要加载的 SWF,您必 须创建一个 LoaderContext 对象来指定主应用程序域,并将该 LoaderContext 对象传递给 Loader.load() 方法调用。如 果要加载的 SWF 所处的应用程序域与主 SWF 应用程序域不同,便会发生错误。即使加载的 SWF 只包含可视资源而不包 含 ActionScript 代码,也是这样。 下例中的代码将一个 SWF 从应用程序包中加载到主 SWF 应用程序域中:168ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 var loader:Loader = new Loader(); var url:URLRequest = new URLRequest("swfs/SecondarySwf.swf"); var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain, null); loader.load(url, loaderContext); 对于只包含资源而不包含代码的 SWF 文件,可以从应用程序包加载,也可以通过网络加载。无论哪一种情况,都必须仍将 SWF 文件加载到主应用程序域中。 对于 AIR 3.6 之前的版本,在编译过程期间,所有代码都是从非主应用程序 SWF 中去除。只包含可视资源的 SWF 文件可以 包括在应用程序包中并在运行时加载,但对于包含代码的 SWF 不是这样。如果要加载的 SWF 包含 ActionScript 代码,便会 发生错误。该错误会导致应用程序中出现一个 “ 未编译的 ActionScript” 错误对话框。 另请参见 在 iOS 上的 AIR 应用程序中打包并加载多个 SWF 使用 ProLoader 和 ProLoaderInfo 类 Flash Player 9 和更高版本、 Adobe AIR 1.0 和更高版本,并且需要 Flash Professional CS5.5 为了帮助预加载运行时共享库 (RSL),Flash Professional CS5.5 引入了 fl.display.ProLoader 和 fl.display.ProLoaderInfo 类。这些类会镜像 flash.display.Loader 和 flash.display.LoaderInfo 类,但提供了更加一致的加载体验。 特别是, ProLoader 可帮助您加载使用 Text Layout Framework (TLF) 执行 RSL 预加载的 SWF 文件。在运行时,预加载 其他 SWF 文件或 SWZ 文件(例如 TLF)的 SWF 文件需要仅供内部使用的 SWF 包装文件。SWF 包装文件会增加调用结构 的复杂性,并可能产生不必要的行为。 ProLoader 可以消除这种复杂关系,它可以像加载普通 SWF 文件那样加载这些文件。 ProLoader 类使用的解决方法对于用户来说是透明的,不需要在 ActionScript 中执行任何特殊处理。此外, ProLoader 还可 以正确加载普通 SWF 内容。 在 Flash Professional CS 5.5 和更高版本中,您可以安全地将所有 Loader 类替换为 ProLoader 类。然后,将您的应用程序 导出到 Flash Player 10.2 或更高版本,以便 ProLoader 能够访问所需的 ActionScript 功能。您也可以在面向支持 ActionScript 3.0 的 Flash Player 早期版本的应用程序中使用 ProLoader。但是只有在 Flash Player 10.2 或更高版本中才能 充分利用 ProLoader 的强大功能。当您在 Flash Professional CS5.5 或更高版本中使用 TLF 时,请始终使用 ProLoader。在 Flash Professional 之外的环境中,不需要使用 ProLoader。 重要说明: 对于在 Flash Professional CS5.5 和更高版本中发布的 SWF 文件,您可以始终使用 fl.display.ProLoader 和 fl.display.ProLoaderInfo 类,而不要使用 flash.display.Loader 和 flash.display.LoaderInfo。 ProLoader 类解决的问题 ProLoader 类解决了此前 Loader 类无法处理的问题。这些问题是在对 TLF 库执行 RSL 预加载的过程中产生的。具体来说, 在使用 Loader 对象加载其他 SWF 文件的 SWF 文件中会碰到这些问题。解决的问题包括: • 加载文件和被加载文件之间的脚本处理无法按预期方式执行。 ProLoader 类会自动将加载 SWF 文件设置为被加载 SWF 文件 的父项。因此,来自加载 SWF 文件的通信会直接转到被加载 SWF 文件。 • SWF 应用程序必须主动管理加载过程。要进行主动管理,需要实现额外的事件,例如 added、 removed、 addedToStage 和 removedFromStage。如果您的应用程序是面向 Flash Player 10.2 或更高版本,则 ProLoader 可消除这些额外的工作。 更新代码,使用 ProLoader 来替代 Loader 由于 ProLoader 会镜像 Loader 类,您可以轻松地在代码中切换这两个类。下面的示例显示了如何更新现有代码以使用新类:169ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 import flash.display.Loader; import flash.events.Event; var l:Loader = new Loader(); addChild(l); l.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete); l.load("my.swf"); function loadComplete(e:Event) { trace('load complete!'); } 可将此代码更新为使用 ProLoader,如下所示: import fl.display.ProLoader; import flash.events.Event; var l:ProLoader = new ProLoader(); addChild(l); l.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete); l.load("my.swf"); function loadComplete(e:Event) { trace('load complete!'); } 显示对象示例:SpriteArranger Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 SpriteArranger 示例应用程序构建在 《学习 ActionScript 3.0》中单独介绍的几何形状示例应用程序的基础上。 SpriteArranger 范例应用程序演示说明了处理显示对象的许多概念: • 扩展显示对象类 • 在显示列表中添加对象 • 分层显示对象和使用显示对象容器 • 响应显示对象事件 • 使用显示对象的属性和方法 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可在文件夹 Examples/SpriteArranger 中找到 SpriteArranger 应用程序文件。该应用程序包含以下文件: 文件 说明 SpriteArranger.mxml 或 SpriteArranger.fla Flash 或 Flex 中的主应用程序文件 (分别为 FLA 和 MXML)。 com/example/programmingas3/SpriteArranger/CircleSprite.as 定义一种 Sprite 对象的类,该种对象在屏幕上呈示为 圆。 com/example/programmingas3/SpriteArranger/DrawingCanvas.as 定义画布的类,画布是包含 GeometricSprite 对象的 显示对象容器。 com/example/programmingas3/SpriteArranger/SquareSprite.as 定义一种 Sprite 对象的类,该对象在屏幕上呈示为正 方形。170ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 定义 SpriteArranger 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 用户可以使用 SpriteArranger 应用程序在屏幕 “ 画布 ” 上添加各种显示对象。 DrawingCanvas 类用于定义绘制区 (一种显示对象容器),用户可以在其中添加屏幕形状。这些屏幕形状是 GeometricSprite 类的其中一个子类的实例。 DrawingCanvas 类 在 Flex 中,添加到 Container 对象的所有子显示对象都必须属于源自 mx.core.UIComponent 类的类。此应用程序将 DrawingCanvas 类的实例添加为 mx.containers.VBox 对象的子级,该对象在 SpriteArranger.mxml 文件的 MXML 代码 中定义。此继承在 DrawingCanvas 类声明中定义,如下所示: public class DrawingCanvas extends UIComponent UIComponent 类继承自 DisplayObject、DisplayObjectContainer 和 Sprite 类,DrawingCanvas 类中的代码使用这些类 的方法和属性。 DrawingCanvas 类扩展了 Sprite 类,此继承是在 DrawingCanvas 类声明中定义的,如下所示: public class DrawingCanvas extends Sprite Sprite 类是 DisplayObjectContainer 和 DisplayObject 类的子类, DrawingCanvas 类使用这些类的方法和属性。 DrawingCanvas() 构造函数方法设置 Rectangle 对象 bounds,它是以后在绘制画布轮廓时使用的属性。然后调用 initCanvas() 方法,如下所示: this.bounds = new Rectangle(0, 0, w, h); initCanvas(fillColor, lineColor); 如下面的示例所示, initCanvas() 方法用于定义 DrawingCanvas 对象的各种属性,这些属性作为参数传递给构造函数: com/example/programmingas3/SpriteArranger/TriangleSprite.as 定义一种 Sprite 对象的类,该对象在屏幕上呈示为三 角形。 com/example/programmingas3/SpriteArranger/GeometricSprite.as 扩展 Sprite 对象的类,用于定义屏幕形状。 CircleSprite、 SquareSprite 和 TriangleSprite 都扩 展此类。 com/example/programmingas3/geometricshapes/IGeometricShape.as 一个基接口,用于定义要由所有几何形状类实现的方 法。 com/example/programmingas3/geometricshapes/IPolygon.as 一个接口,用于定义要由具有多条边的几何形状类实现 的方法。 com/example/programmingas3/geometricshapes/RegularPolygon.as 一种几何形状,这种几何形状的边长相等,并且这些边 围绕形状中心对称分布。 com/example/programmingas3/geometricshapes/Circle.as 一种用于定义圆的几何形状。 com/example/programmingas3/geometricshapes/EquilateralTriangle.as RegularPolygon 的子类,用于定义所有边长相等的三 角形。 com/example/programmingas3/geometricshapes/Square.as RegularPolygon 的子类,用于定义所有四条边相等的 矩形。 com/example/programmingas3/geometricshapes/GeometricShapeFactory.as 包含 “ 工厂方法 ” 的一个类,用于创建给定了形状类型 和尺寸的形状。 文件 说明171ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 this.lineColor = lineColor; this.fillColor = fillColor; this.width = 500; this.height = 200; initCanvas() 方法随后调用 drawBounds() 方法,后者使用 DrawingCanvas 类的 graphics 属性绘制画布。graphics 属性继承自 Shape 类 this.graphics.clear(); this.graphics.lineStyle(1.0, this.lineColor, 1.0); this.graphics.beginFill(this.fillColor, 1.0); this.graphics.drawRect(bounds.left - 1, bounds.top - 1, bounds.width + 2, bounds.height + 2); this.graphics.endFill(); DrawingCanvas 类的下列附加方法是根据用户与应用程序的交互进行调用的: • addShape() 和 describeChildren() 方法,在第 171 页的 “ 在画布上添加显示对象 ” 中介绍 • moveToBack()、 moveDown()、 moveToFront() 和 moveUp() 方法,在第 173 页的 “ 重新排列显示对象层 ” 中介绍 • onMouseUp() 方法,在第 173 页的 “ 单击并拖动显示对象 ” 中介绍 GeometricSprite 类及其子类 用户在画布上可以添加的每个显示对象都是 GeometricSprite 类以下某个子类的实例: • CircleSprite • SquareSprite • TriangleSprite GeometricSprite 类扩展了 flash.display.Sprite 类: public class GeometricSprite extends Sprite GeometricSprite 类包括所有 GeometricSprite 对象所共有的一些属性。这些属性是根据传递到构造函数的参数,在该函数 中设置的。例如: this.size = size; this.lineColor = lColor; this.fillColor = fColor; GeometricSprite 类的 geometricShape 属性用于定义 IGeometricShape 接口,该接口定义形状的数学属性,但不定义其可视 属性。《学习 ActionScript 3.0》中介绍的 GeometricShapes 示例应用程序中定义了实现 IGeometricShape 接口的类。 GeometricSprite 类用于定义 drawShape() 方法,该方法在 GeometricSprite 的各子类的覆盖定义中已进一步精确定义。有关 详细信息,请参阅后面的 “ 在画布上添加显示对象 ” 一节。 GeometricSprite 类还提供下列方法: • onMouseDown() 和 onMouseUp() 方法,在第 173 页的 “ 单击并拖动显示对象 ” 中介绍 • showSelected() 和 hideSelected() 方法,在第 173 页的 “ 单击并拖动显示对象 ” 中介绍 在画布上添加显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当用户单击 “ 添加形状 ” 按钮时,应用程序将调用 DrawingCanvas 类的 addShape() 方法。它通过调用其中一个 GeometricSprite 子类的相应构造函数来实例化新的 GeometricSprite,如下面的示例所示:172ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 public function addShape(shapeName:String, len:Number):void { var newShape:GeometricSprite; switch (shapeName) { case "Triangle": newShape = new TriangleSprite(len); break; case "Square": newShape = new SquareSprite(len); break; case "Circle": newShape = new CircleSprite(len); break; } newShape.alpha = 0.8; this.addChild(newShape); } 每个构造函数方法都调用 drawShape() 方法,该方法使用类 (继承自 Sprite 类)的 graphics 属性来绘制相应的矢量图形。例 如, CircleSprite 类的 drawShape() 方法包括下列代码: this.graphics.clear(); this.graphics.lineStyle(1.0, this.lineColor, 1.0); this.graphics.beginFill(this.fillColor, 1.0); var radius:Number = this.size / 2; this.graphics.drawCircle(radius, radius, radius); addShape() 函数的倒数第二行用于设置显示对象 (继承自 DisplayObject 类)的 alpha 属性,所以画布上添加的每个显示对象 都有一点儿透明,这样用户就可看见它后面的对象。 addChild() 方法的最后一行用于在 DrawingCanvas 类实例的子级列表中添加新的显示对象,该实例已经在显示列表中。这样 会使新的显示对象出现在舞台上。 应用程序界面上包括两个文本字段 selectedSpriteTxt 和 outputTxt。这些文本字段的文本属性由已添加到画布中或由用户选择的 GeometricSprite 对象的信息更新。 GeometricSprite 类通过覆盖 toString() 方法来处理这种信息报告任务,如下所示: public override function toString():String { return this.shapeType + " of size " + this.size + " at " + this.x + ", " + this.y; } shapeType 属性设置为每个 GeometricSprite 子类的构造函数方法中的相应值。例如, toString() 方法可能返回最近添加到 DrawingCanvas 实例中的 CircleSprite 实例的下列值: Circle of size 50 at 0, 0 DrawingCanvas 类的 describeChildren() 方法通过使用 numChildren 属性 (继承自 DisplayObjectContainer 类)设置 for 循环的限制,来循环访问画布的子级列表。它会生成一个列出了每一子级的字符串,如下所示: var desc:String = ""; var child:DisplayObject; for (var i:int=0; i < this.numChildren; i++) { child = this.getChildAt(i); desc += i + ": " + child + '\n'; } 所得的字符串用于设置 outputTxt 文本字段的 text 属性。173ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 单击并拖动显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当用户单击 GeometricSprite 实例时,应用程序将调用 onMouseDown() 事件处理函数。如下所示,此事件处理函数设置为侦 听 GeometricSprite 类的构造函数中的鼠标按下事件: this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); onMouseDown() 方法随后调用 GeometricSprite 对象的 showSelected() 方法。如果是首次调用该对象的此方法,该方法将创 建名为 selectionIndicator 的新 Shape 对象,并且使用 Shape 对象的 graphics 属性来绘制红色加亮矩形,如下所示: this.selectionIndicator = new Shape(); this.selectionIndicator.graphics.lineStyle(1.0, 0xFF0000, 1.0); this.selectionIndicator.graphics.drawRect(-1, -1, this.size + 1, this.size + 1); this.addChild(this.selectionIndicator); 如果不是首次调用 onMouseDown() 方法,该方法仅设置 selectionIndicator 形状的 visible 属性 (继承自 DisplayObject 类), 如下所示: this.selectionIndicator.visible = true; hideSelected() 方法通过将其 visible 属性设置为 false 来隐藏以前所选对象的 selectionIndicator 形状。 onMouseDown() 事件处理函数方法还会调用 startDrag() 方法 (继承自 Sprite 类),该方法包括下列代码: var boundsRect:Rectangle = this.parent.getRect(this.parent); boundsRect.width -= this.size; boundsRect.height -= this.size; this.startDrag(false, boundsRect); 这样,用户就可以在由 boundsRect 矩形设置的边界内在画布各处拖动选择的对象。 当用户松开鼠标按键时,将调度 mouseUp 事件。 DrawingCanvas 的构造函数方法设置了下列事件侦听器: this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); 此事件侦听器是针对 DrawingCanvas 对象设置的,而不是针对单个 GeometricSprite 对象设置的。这是因为当拖动 GeometricSprite 对象时,松开鼠标后它可能会在另一个显示对象 (另一个 GeometricSprite 对象)之后结束前景中的显示 对象会收到鼠标弹起事件,但用户正在拖动的显示对象则不会收到。在 DrawingCanvas 对象中添加侦听器可以确保始终处理 该事件。 onMouseUp() 方法调用 GeometricSprite 对象的 onMouseUp() 方法,后者又调用 GeometricSprite 对象的 stopDrag() 方法。 重新排列显示对象层 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 应用程序用户界面上包括标有 “ 后移 ”、 “ 下移 ”、 “ 上移 ” 和 “ 移到最前 ” 的按钮。当用户单击其中一个按钮时,应用程序将 调用 DrawingCanvas 类的相应方法:moveToBack()、moveDown()、moveUp() 或 moveToFront()。例如,moveToBack() 方 法包括下面的代码: public function moveToBack(shape:GeometricSprite):void { var index:int = this.getChildIndex(shape); if (index > 0) { this.setChildIndex(shape, 0); } }174ACTIONSCRIPT 3.0 开发人员指南 显示编程 上次更新 2014/12/1 该方法使用 setChildIndex() 方法(继承自 DisplayObjectContainer 类)确定显示对象位置在 DrawingCanvas 实例 (this) 的 子级列表中的索引位置 0 处。 moveDown() 方法的作用类似,不同的是它将显示对象在 DrawingCanvas 实例的子级列表中的索引位置减少 1: public function moveDown(shape:GeometricSprite):void { var index:int = this.getChildIndex(shape); if (index > 0) { this.setChildIndex(shape, index - 1); } } moveUp() 和 moveToFront() 方法的作用与 moveToBack() 和 moveDown() 方法类似。175 上次更新 2014/12/1 第 11 章 : 使用几何结构 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 flash.geom 包中包含用于定义几何对象 (如,点、矩形和转换矩阵)的类。您可使用这些类来定义在其他类中使用的对象的 属性。 更多帮助主题 flash.geom 包 几何结构基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 flash.geom 包中包含用于定义几何对象 (如,点、矩形和转换矩阵)的类。这些类本身并不一定提供功能,但它们用于定义 在其他类中使用的对象的属性。 所有几何类都基于以下概念:将屏幕上的位置表示为二维平面。可以将屏幕看作是具有水平 (x) 轴和垂直 (y) 轴的平面图形。 屏幕上的任何位置 (或 “ 点 ”)可以表示为 x 和 y 值对,即该位置的 “ 坐标 ”。 每个显示对象 (包括 Stage)都有自己的坐标空间。坐标空间是对象自己的图形,用于绘制子显示对象、绘图等的位置。原点 的坐标位置为 0, 0 (X 和 Y 轴在此处相交),位于显示对象的左上角。此原点位置始终适用于舞台,但对于其他显示对象则不 一定适用。 X 轴上的值越大越偏向右侧,越小越偏向左侧。对于原点左侧的位置, X 坐标是负数。然而,与传统的坐标系相 反, Flash 运行时在 Y 轴的坐标值越大越偏向屏幕下方,越小越偏向屏幕上方。原点上侧的值为负的 Y 坐标值。因为舞台的左 上角是其坐标空间的原点,所以舞台上大多数对象的 X 坐标值大于 0 但小于舞台宽度。而且同一个对象的 Y 坐标值大于 0 但小 于舞台高度。 可以使用 Point 类实例来表示坐标空间中的各个点。您可以创建一个 Rectangle 实例来表示坐标空间中的矩形区域。对于高级 用户,可以使用 Matrix 实例将多个或复杂变形应用于显示对象。通过使用显示对象的属性,可以将很多简单变形 (如旋转、 位置以及缩放变化)直接应用于该对象。有关使用显示对象属性应用变形的详细信息,请参阅第 144 页的 “ 处理显示对象 ”。 重要概念和术语 以下参考列表包含重要的几何术语: 笛卡尔坐标 坐标通常写为一对数字 (例如 5, 12 或 17, -23)。两个数字分别是 x 坐标和 y 坐标。 坐标空间 包含在显示对象中的坐标的图形,显示对象的子元素位于该坐标位置处。 原点 坐标空间中位于 X 轴和 Y 轴相交处的点。该点的坐标为 0, 0。 点 坐标空间中的一个位置。在 ActionScript 使用的二维坐标系中,沿 X 轴和 Y 轴的位置 (点的坐标)定义点。 注册点 显示对象中,坐标空间的原点 (0, 0 坐标)。 缩放 对象的大小,相对于其原始大小。用作动词时,对象缩放是指伸展或缩小对象以更改其大小。 转换 将点的坐标从一个坐标空间更改到另一个坐标空间。 转换 对图形的视觉特性的调整,例如旋转对象、更改其比例、倾斜或扭曲其形状或改变其颜色。 X 轴 ActionScript 中使用的二维坐标系中的横轴。 Y 轴 ActionScript 中使用的二维坐标系中的纵轴。176ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 使用 Point 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Point 对象定义一对笛卡尔坐标。它表示二维坐标系中的某个位置。其中 x 表示水平轴, y 表示垂直轴。 要定义 Point 对象,请设置它的 x 和 y 属性,如下所示: import flash.geom.*; var pt1:Point = new Point(10, 20); // x == 10; y == 20 var pt2:Point = new Point(); pt2.x = 10; pt2.y = 20; 确定两点之间的距离 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 Point 类的 distance() 方法确定坐标空间两点之间的距离。例如,下面的代码确定同一显示对象容器中两个显示对象 (circle1 和 circle2)的注册点之间的距离: import flash.geom.*; var pt1:Point = new Point(circle1.x, circle1.y); var pt2:Point = new Point(circle2.x, circle2.y); var distance:Number = Point.distance(pt1, pt2); 平移坐标空间 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如果两个显示对象位于不同的显示对象容器中,则两者可能位于不同的坐标空间中。您可以使用 DisplayObject 类的 localToGlobal() 方法将坐标平移到舞台中相同 (全局)坐标空间。例如,下面的代码确定不同显示对象容器中两个显示对象 (circle1 和 circle2)的注册点之间的距离: import flash.geom.*; var pt1:Point = new Point(circle1.x, circle1.y); pt1 = circle1.localToGlobal(pt1); var pt2:Point = new Point(circle2.x, circle2.y); pt2 = circle2.localToGlobal(pt2); var distance:Number = Point.distance(pt1, pt2); 同样,要查找名为 target 的显示对象的注册点与舞台上特定点间的距离,请使用 DisplayObject 类的 localToGlobal() 方法: import flash.geom.*; var stageCenter:Point = new Point(); stageCenter.x = this.stage.stageWidth / 2; stageCenter.y = this.stage.stageHeight / 2; var targetCenter:Point = new Point(target.x, target.y); targetCenter = target.localToGlobal(targetCenter); var distance:Number = Point.distance(stageCenter, targetCenter); 按指定的角度和距离移动显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 您可以使用 Point 类的 polar() 方法将显示对象按特定角度移动特定距离。例如,下列代码按 60° 角度将 myDisplayObject 对象 移动 100 像素: 177ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 import flash.geom.*; var distance:Number = 100; var angle:Number = 2 * Math.PI * (90 / 360); var translatePoint:Point = Point.polar(distance, angle); myDisplayObject.x += translatePoint.x; myDisplayObject.y += translatePoint.y; Point 类的其他用法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 您可以将 Point 对象用于以下方法和属性: 使用 Rectangle 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Rectangle 对象定义一个矩形区域。Rectangle 对象有具体的位置,该位置由其左上角的 x 和 y 坐标以及 width 属性和 height 属性定义。您可以按照如下方式通过调用 Rectangle() 构造函数来为新 Rectangle 对象定义这些属性: import flash.geom.Rectangle; var rx:Number = 0; var ry:Number = 0; var rwidth:Number = 100; var rheight:Number = 50; var rect1:Rectangle = new Rectangle(rx, ry, rwidth, rheight); 类 方法或属性 说明 DisplayObjectContainer areInaccessibleObjectsUnderPoint()getObjectsUnderPo int() 用于返回显示对象容器中某个点下的对象的列表。 BitmapData hitTest() 用于定义 BitmapData 对象中的像素以及要检查点 击的点。 BitmapData applyFilter() copyChannel() merge() paletteMap() pixelDissolve() threshold() 用于定义那些定义操作的矩形的位置。 Matrix deltaTransformPoint() transformPoint() 用于定义您要对其应用变形的点。 Rectangle bottomRight size topLeft 用于定义这些属性。178ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 调整 Rectangle 对象的大小和进行重新定位 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 有多种方法调整 Rectangle 对象的大小和进行重新定位。 您可以通过更改 Rectangle 对象的 x 和 y 属性直接重新定位该对象。此更改不会影响 Rectangle 对象的宽度或高度。 import flash.geom.Rectangle; var x1:Number = 0; var y1:Number = 0; var width1:Number = 100; var height1:Number = 50; var rect1:Rectangle = new Rectangle(x1, y1, width1, height1); trace(rect1) // (x=0, y=0, w=100, h=50) rect1.x = 20; rect1.y = 30; trace(rect1); // (x=20, y=30, w=100, h=50) 如下面的代码所示,当更改 Rectangle 对象的 left 或 top 属性时,将重新定位该矩形。矩形的 x 和 y 属性分别与 left 和 top 属性 匹配。然而, Rectangle 对象的左下角的位置不发生改变,因此调整了该对象的大小。 import flash.geom.Rectangle; var x1:Number = 0; var y1:Number = 0; var width1:Number = 100; var height1:Number = 50; var rect1:Rectangle = new Rectangle(x1, y1, width1, height1); trace(rect1) // (x=0, y=0, w=100, h=50) rect1.left = 20; rect1.top = 30; trace(rect1); // (x=20, y=30, w=80, h=20) 同样,如下面的示例所示,如果更改 Rectangle 对象的 bottom 或 right 属性,该对象左上角的位置不发生改变。矩形相应地调 整了大小: import flash.geom.Rectangle; var x1:Number = 0; var y1:Number = 0; var width1:Number = 100; var height1:Number = 50; var rect1:Rectangle = new Rectangle(x1, y1, width1, height1); trace(rect1) // (x=0, y=0, w=100, h=50) rect1.right = 60; trect1.bottom = 20; trace(rect1); // (x=0, y=0, w=60, h=20) 也可以使用 offset() 方法重新定位 Rectangle 对象,如下所示: import flash.geom.Rectangle; var x1:Number = 0; var y1:Number = 0; var width1:Number = 100; var height1:Number = 50; var rect1:Rectangle = new Rectangle(x1, y1, width1, height1); trace(rect1) // (x=0, y=0, w=100, h=50) rect1.offset(20, 30); trace(rect1); // (x=20, y=30, w=100, h=50) offsetPt() 方法工作方式类似,只不过它是将 Point 对象作为参数,而不是将 x 和 y 偏移量值作为参数。 还可以使用 inflate() 方法调整 Rectangle 对象的大小,该方法包含两个参数, dx 和 dy。 dx 参数表示矩形的左侧和右侧距离中 心的像素数。 dy 参数表示矩形的顶部和底部距离中心的像素数:179ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 import flash.geom.Rectangle; var x1:Number = 0; var y1:Number = 0; var width1:Number = 100; var height1:Number = 50; var rect1:Rectangle = new Rectangle(x1, y1, width1, height1); trace(rect1) // (x=0, y=0, w=100, h=50) rect1.inflate(6,4); trace(rect1); // (x=-6, y=-4, w=112, h=58) inflatePt() 方法作方式类似,只不过它是将 Point 对象作为参数,而不是将 dx 和 dy 的值作为参数。 确定 Rectangle 对象的联合和交集 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 union() 方法来确定由两个矩形的边界形成的矩形区域: import flash.display.*; import flash.geom.Rectangle; var rect1:Rectangle = new Rectangle(0, 0, 100, 100); trace(rect1); // (x=0, y=0, w=100, h=100) var rect2:Rectangle = new Rectangle(120, 60, 100, 100); trace(rect2); // (x=120, y=60, w=100, h=100) trace(rect1.union(rect2)); // (x=0, y=0, w=220, h=160) 可以使用 intersection() 方法来确定由两个矩形重叠区域形成的矩形区域: import flash.display.*; import flash.geom.Rectangle; var rect1:Rectangle = new Rectangle(0, 0, 100, 100); trace(rect1); // (x=0, y=0, w=100, h=100) var rect2:Rectangle = new Rectangle(80, 60, 100, 100); trace(rect2); // (x=120, y=60, w=100, h=100) trace(rect1.intersection(rect2)); // (x=80, y=60, w=20, h=40) 使用 intersects() 方法查明两个矩形是否相交。也可以使用 intersects() 方法查明显示对象是否在舞台的某个区域中。对于下列代 码示例,假设包含 circle 对象的显示对象容器的坐标空间与舞台的坐标空间相同。本示例说明如何使用 intersects() 方法来确定 显示对象 circle 是否与由 target1 和 target2 Rectangle 对象定义的指定舞台区域相交: import flash.display.*; import flash.geom.Rectangle; var circle:Shape = new Shape(); circle.graphics.lineStyle(2, 0xFF0000); circle.graphics.drawCircle(250, 250, 100); addChild(circle); var circleBounds:Rectangle = circle.getBounds(stage); var target1:Rectangle = new Rectangle(0, 0, 100, 100); trace(circleBounds.intersects(target1)); // false var target2:Rectangle = new Rectangle(0, 0, 300, 300); trace(circleBounds.intersects(target2)); // true 同样,可以使用 intersects() 方法查明两个显示对象的边界矩形是否重叠。使用 DisplayObject 类的 getRect() 方法来包括显示 对象的笔触添加到边界区域的其他任何空间。 Rectangle 对象的其他用法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Rectangle 对象可用于以下方法和属性:180ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 使用 Matrix 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Matrix 类表示一个转换矩阵,它确定如何将点从一个坐标空间映射到另一个坐标空间。您可以对一个显示对象执行不同的图形 转换,方法是设置 Matrix 对象的属性,将该 Matrix 对象应用于 Transform 对象的 matrix 属性,然后应用该 Transform 对 象作为显示对象的 transform 属性。 这些转换函数包括平移 (x 和 y 重新定位)、旋转、缩放和倾斜。 虽然可以通过直接调整 Matrix 对象的属性(a、b、c、d、tx 和 ty)来定义矩阵,但更简单的方法是使用 createBox() 方法。使 用此方法提供的参数可以直接定义生成的矩阵的缩放、旋转和平移效果。例如,以下代码创建一个 Matrix 对象,该对象可将 某个对象水平缩放 2.0、垂直缩放 3.0、旋转 45°、向右移动 (转换) 10 像素并向下移动 20 像素: var matrix:Matrix = new Matrix(); var scaleX:Number = 2.0; var scaleY:Number = 3.0; var rotation:Number = 2 * Math.PI * (45 / 360); var tx:Number = 10; var ty:Number = 20; matrix.createBox(scaleX, scaleY, rotation, tx, ty); 还可以使用 scale()、 rotate() 和 translate() 方法调整 Matrix 对象的缩放、旋转和平移效果。请注意,这些方法合并了现有 Matrix 对象的值。例如,以下代码设置一个 Matrix 对象,该对象可将某个对象按缩放系数 4 进行缩放并旋转 60°,因为 scale() 和 rotate() 方法会调用两次: var matrix:Matrix = new Matrix(); var rotation:Number = 2 * Math.PI * (30 / 360); // 30° var scaleFactor:Number = 2; matrix.scale(scaleFactor, scaleFactor); matrix.rotate(rotation); matrix.scale(scaleX, scaleY); matrix.rotate(rotation); myDisplayObject.transform.matrix = matrix; 要将倾斜转换应用到 Matrix 对象,请调整该对象的 b 或 c 属性。调整 b 属性将矩阵垂直倾斜,并调整 c 属性将矩阵水平倾斜。 以下代码使用系数 2 垂直倾斜 myMatrix Matrix 对象: var skewMatrix:Matrix = new Matrix(); skewMatrix.b = Math.tan(2); myMatrix.concat(skewMatrix); 可以将矩阵转换应用到显示对象的 transform 属性。例如,以下代码将矩阵转换应用于名为 myDisplayObject 的显示对象: 类 方法或属性 说明 BitmapData applyFilter()、 colorTransform()、 copyChannel()、 copyPixels()、 draw()、 drawWithQuality()、 encode()、 fillRect()、 generateFilterRect()、 getColorBoundsRect()、 getPixels()、 merge()、 paletteMap()、 pixelDissolve()、 setPixels() 和 threshold() 用作某些参数的类型以定义 BitmapData 对象的区域。 DisplayObject getBounds()、 getRect()、 scrollRect、 scale9Grid 用作属性的数据类型或返回的数据类型。 PrintJob addPage() 用于定义 printArea 参数。 Sprite startDrag() 用于定义 bounds 参数。 TextField getCharBoundaries() 用作返回值类型。 Transform pixelBounds 用作数据类型。181ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 var matrix:Matrix = myDisplayObject.transform.matrix; var scaleFactor:Number = 2; var rotation:Number = 2 * Math.PI * (60 / 360); // 60° matrix.scale(scaleFactor, scaleFactor); matrix.rotate(rotation); myDisplayObject.transform.matrix = matrix; 第一行将 Matrix 对象设置为 myDisplayObject 显示对象所使用的现有转换矩阵 (myDisplayObject 显示对象的 transformation 属性的 matrix 属性)。这样,调用的 Matrix 类方法对显示对象的现有位置、缩放和旋转会产生累积效果。 注: ColorTransform 类还包含在 flash.geometry 包中。该类用于设置 Transform 对象的 colorTransform 属性。因为它不应 用任何几何转换,所以在此处不做详细讨论。有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中 的 ColorTransform 类。 几何形状示例:对显示对象应用矩阵转换 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 DisplayObjectTransformer 范例应用程序说明许多使用 Matrix 类来变换显示对象的功能,包括: • 旋转显示对象 • 缩放显示对象 • 平移 (重新定位)显示对象 • 倾斜显示对象 该应用程序提供了接口,以调整矩阵转换的参数,如下所示: 当用户单击 “ 变形 ” 按钮时,应用程序将应用适当的变形。182ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 原始显示对象和旋转了 -45° 并缩放 50% 的显示对象 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在 Samples/DisplayObjectTransformer 中找到 DisplayObjectTransformer 应用程序文件。该应用程序包含以下文件: 定义 MatrixTransformer 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 MatrixTransformer 类包含应用 Matrix 对象的几何变形的静态方法。 transform() 方法 transform() 方法包含以下属性的参数: • sourceMatrix — 此方法转换的输入矩阵 • xScale 和 yScale — x 和 y 缩放系数 • dx 和 dy — x 和 y 平移量 (以像素为单位) • rotation — 旋转量 (以度为单位) • skew — 倾斜系数 (以百分比表示) • skewType — 倾斜的方向, "right" 或 "left" 返回值为生成的矩阵。 transform() 方法调用下列类的静态方法: • skew() • scale() • translate() • rotate() 每种方法都返回应用了转换的源矩阵。 文件 说明 DisplayObjectTransformer.mxml 或 DisplayObjectTransformer.fla Flash (FLA) 或 Flex (MXML) 中的主应用程序文件 com/example/programmingas3/geometry/MatrixTransformer.as 一个类,包含用于应用矩阵转换的方法。 img/ 一个目录,包含应用程序使用的范例图像文件。183ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 skew() 方法 skew() 方法通过调整矩阵的 b 和 c 属性来倾斜矩阵。可选参数 unit 确定用于定义倾斜角度的单位,如果必要,该方法会将 angle 值转换为弧度: if (unit == "degrees") { angle = Math.PI * 2 * angle / 360; } if (unit == "gradients") { angle = Math.PI * 2 * angle / 100; } 创建并调整 skewMatrix Matrix 对象以应用倾斜转换。最初,它是恒等矩阵,如下所示: var skewMatrix:Matrix = new Matrix(); skewSide 参数确定倾斜应用到的边。如果该参数设置为 "right",则以下代码设置矩阵的 b 属性: skewMatrix.b = Math.tan(angle); 否则,将通过调整矩阵的 c 属性来倾斜底边,如下所示: skewMatrix.c = Math.tan(angle); 然后,通过将两个矩阵连接起来以将所产生的倾斜应用到现有矩阵,如下面的示例所示: sourceMatrix.concat(skewMatrix); return sourceMatrix; scale() 方法 下面的示例显示 scale() 方法首先会调整缩放系数 (如果提供的缩放系数为百分比),然后使用矩阵对象的 scale() 方法: if (percent) { xScale = xScale / 100; yScale = yScale / 100; } sourceMatrix.scale(xScale, yScale); return sourceMatrix; translate() 方法 translate() 方法只需通过调用矩阵对象的 translate() 方法即可应用 dx 和 dy 平移系数,如下所示: sourceMatrix.translate(dx, dy); return sourceMatrix; rotate() 方法 rotate() 方法将输入的旋转系数转换为弧度 (如果提供的是角度或渐变),然后调用矩阵对象的 rotate() 方法: if (unit == "degrees") { angle = Math.PI * 2 * angle / 360; } if (unit == "gradients") { angle = Math.PI * 2 * angle / 100; } sourceMatrix.rotate(angle); return sourceMatrix;184ACTIONSCRIPT 3.0 开发人员指南 使用几何结构 上次更新 2014/12/1 从应用程序中调用 MatrixTransformer.transform() 方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 应用程序提供了一个用户界面,以便从用户处获得转换参数。然后将这些值与显示对象的 transform 属性的 matrix 属性一起传 递给 Matrix.transform() 方法,如下所示: tempMatrix = MatrixTransformer.transform(tempMatrix, xScaleSlider.value, yScaleSlider.value, dxSlider.value, dySlider.value, rotationSlider.value, skewSlider.value, skewSide ); 应用程序随后将返回值应用到显示对象的 transform 属性的 matrix 属性,从而触发转换: img.content.transform.matrix = tempMatrix;185 上次更新 2014/12/1 第 12 章 : 使用绘图 API Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 虽然导入的图像和插图非常重要,但您可以使用一项称为绘图 API 的功能 (用于在 ActionScript 中绘制线条和形状)随时启 动计算机中的应用程序,这就相当于一个空白画布,您可以在上面创建所需的任何图像。能够创建自己的图形可为您的应用程 序提供广阔的前景。使用此处介绍的方法,您可以完成许多工作,如创建绘图程序、制作交互的动画效果,或以编程方式创建 您自己的用户界面元素,等等。 更多帮助主题 flash.display.Graphics 绘制 API 的基础 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 绘图 API 是 ActionScript 中一项内置功能的名称,您可以使用该功能来创建矢量图形 (直线、曲线、形状、填充和渐变), 并使用 ActionScript 在屏幕上显示它们。 flash.display.Graphics 类提供了这一功能。您可以在任何 Shape、 Sprite 或 MovieClip 实例中使用 ActionScript 进行绘制(使用在这每个类中定义的 graphics 属性)。(实际上,这每个类的 graphics 属 性都是 Graphics 类的实例。) 如果刚刚开始学习使用代码进行绘制,可以使用 Graphics 类中包含的几种方法来简化常见形状 (如圆、椭圆、矩形以及带圆 角的矩形)的绘制过程。您可以将它们作为空线条或填充形状进行绘制。当您需要更高级的功能时, Graphics 类还提供了用 于绘制直线和二次贝塞尔曲线的方法,您可以将这些方法与 Math 类中的三角函数配合使用,创建所需的任何形状。 Flash 运行时(如 Flash Player 10 和 Adobe AIR 1.5 及更高版本)增加了一个绘图 API,通过该 API,只需一个命令即可用 编程方式绘制完整的形状。熟悉 Graphics 类以及 “ 绘图 API 使用基础知识 ” 中介绍的任务后,请继续学习第 196 页的 “ 绘图 API 高级用法 ”,了解有关这些绘图 API 功能的详细信息。 重要概念和术语 以下参考列表包含使用绘图 API 时会遇到的重要术语: 锚点 二次贝塞尔曲线的两个端点之一。 控制点 该点定义二次贝塞尔曲线的弯曲方向和弯曲量。弯曲的线绝不会到达控制点;但曲线就好像朝着控制点方向进行绘制 的。 坐标空间 包含在显示对象中的坐标的图形,显示对象的子元素位于该坐标位置处。 填充 用颜色填充了线条的形状的内部实体部分,或没有外框的整个形状。 渐变 此颜色是指从一种颜色逐渐过渡到一种或多种其他颜色 (与纯色相对)。 点 坐标空间中的一个位置。在 ActionScript 使用的二维坐标系中,点是按其 x 轴和 y 轴位置 (点坐标)来定义的。 二次贝塞尔曲线 由特定的数学公式定义的曲线类型。在这种类型的曲线中,曲线形状根据锚点 (曲线端点)和控制点 (定义 曲线的弯曲方向和弯曲量)的位置来计算。 缩放 对象的大小,相对于其原始大小。用作动词时,对象缩放是指伸展或缩小对象以更改其大小。 笔触 用颜色填充了线条的形状的外框部分,或未填充形状的线条。 转换 将点的坐标从一个坐标空间更改到另一个坐标空间。186ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 X 轴 ActionScript 中使用的二维坐标系中的横轴。 Y 轴 ActionScript 中使用的二维坐标系中的纵轴。 Graphics 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 每个 Shape、Sprite 和 MovieClip 对象都具有一个 graphics 属性,它是 Graphics 类的一个实例。Graphics 类包含用于绘制线条、填充 和形状的属性和方法。如果要将显示对象仅用作内容绘制画布,则可以使用 Shape 实例。Shape 实例的性能优于其他用于绘制 的显示对象,因为它不会产生 Sprite 和 MovieClip 类中的附加功能的开销。如果希望能够在显示对象上绘制图形内容,并且 还希望该对象包含其他显示对象,则可以使用 Sprite 实例。有关确定用于各种任务的显示对象的详细信息,请参阅第 143 页的 “ 选择 DisplayObject 子类 ”。 绘制线条和曲线 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用 Graphics 实例进行的所有绘制均基于包含线条和曲线的基本绘制。因此,必须使用一系列相同的步骤来执行所有 ActionScript 绘制: • 定义线条和填充样式 • 设置初始绘制位置 • 绘制线条、曲线和形状 (可选择移动绘制点) • 如有必要,完成创建填充 定义线条和填充样式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 要使用 Shape、 Sprite 或 MovieClip 实例的 graphics 属性进行绘制,您必须先定义在绘制时使用的样式 (线条大小和颜色、 填充颜色)。就像使用 Adobe® Flash® Professional 或其他绘图应用程序中的绘制工具一样,使用 ActionScript 进行绘制时, 可以使用笔触进行绘制,也可以不使用笔触;可以使用填充颜色进行绘制,也可以不使用填充颜色。您可以使用 lineStyle() 或 lineGradientStyle() 方法来指定笔触的外观。要创建纯色线条,请使用 lineStyle() 方法。调用此方法时,您指定的最常用的值是 前三个参数:线条粗细、颜色以及 Alpha。例如,该行代码指示名为 myShape 的 Shape 对象绘制 2 个像素粗、红色 (0x990000) 以及 75% 不透明的线条: myShape.graphics.lineStyle(2, 0x990000, .75); Alpha 参数的默认值为 1.0 (100%),因此,如果需要完全不透明的线条,可以将该参数的值保持不变。 lineStyle() 方法还接受 另外两个参数,分别对应于像素提示和缩放模式;有关使用这些参数的详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中 Graphics.lineStyle() 方法的说明。 要创建渐变线条,请使用 lineGradientStyle() 方法。关于此方法的介绍请参阅第 189 页的 “ 创建渐变线条和填充 ”。 如果要创建填充形状,请在开始绘制之前调用 beginFill()、beginGradientFill()、beginBitmapFill() 或 beginShaderFill() 方法。其 中的最基本方法 beginFill() 接受以下两个参数:填充颜色以及填充颜色的 Alpha 值 (可选)。例如,如果要绘制具有纯绿色填 充的形状,应使用以下代码 (假设在名为 myShape 的对象上进行绘制): myShape.graphics.beginFill(0x00FF00);187ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 调用任何填充方法时,将隐式地结束任何以前的填充,然后再开始新的填充。调用任何指定笔触样式的方法时,将替换以前的 笔触,但不会改变以前指定的填充,反之亦然。 指定了线条样式和填充属性后,下一步是指示绘制的起始点。 Graphics 实例具有一个绘制点,就像在一张纸上的钢笔尖一样。 无论绘制点位于什么位置,它都是开始执行下一个绘制动作的位置。最初, Graphics 对象将它绘制时所在对象的坐标空间中 的点 (0, 0) 作为起始绘制点。要在其他点开始进行绘制,您可以先调用 moveTo() 方法,然后再调用绘制方法之一。这类似于将 钢笔尖从纸上抬起,然后将其移到新位置。 确定绘制点后,可通过使用对绘制方法 lineTo() (用于绘制直线)和 curveTo() (用于绘制曲线)的一系列调用来进行绘制。 在进行绘制时,可随时调用 moveTo() 方法,将绘制点移到新位置而不进行绘制。 进行绘制时,如果您已指定填充颜色,可以通过调用 endFill() 方法关闭填充。如果绘制的不是闭合的形状 (即,调用 endFill() 时绘制点不在形状的起始点),则调用 endFill() 方法时, Flash 运行时将自动绘制一条直线以使形状闭合,该直线从当前绘制 点到最近一次 moveTo() 调用中指定的位置。如果已开始填充并且没有调用 endFill(),调用 beginFill() (或其他填充方法之一) 时,将关闭当前填充并开始新的填充。 绘制直线 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 调用 lineTo() 方法时,Graphics 对象将绘制一条直线,该直线从当前绘制点到指定为方法调用中的两个参数的坐标,以便使用 指定的线条样式进行绘制。例如,该行代码将绘制点放在点 (100, 100) 上,然后绘制一条到点 (200, 200) 的直线: myShape.graphics.moveTo(100, 100); myShape.graphics.lineTo(200, 200); 以下示例绘制红色和绿色三角形,其高度为 100 个像素: var triangleHeight:uint = 100; var triangle:Shape = new Shape(); // red triangle, starting at point 0, 0 triangle.graphics.beginFill(0xFF0000); triangle.graphics.moveTo(triangleHeight / 2, 0); triangle.graphics.lineTo(triangleHeight, triangleHeight); triangle.graphics.lineTo(0, triangleHeight); triangle.graphics.lineTo(triangleHeight / 2, 0); // green triangle, starting at point 200, 0 triangle.graphics.beginFill(0x00FF00); triangle.graphics.moveTo(200 + triangleHeight / 2, 0); triangle.graphics.lineTo(200 + triangleHeight, triangleHeight); triangle.graphics.lineTo(200, triangleHeight); triangle.graphics.lineTo(200 + triangleHeight / 2, 0); this.addChild(triangle); 绘制曲线 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 curveTo() 方法可以绘制二次贝塞尔曲线。这将绘制一个连接两个点 (称为锚点)的弧,同时向第三个点 (称为控制点)弯 曲。 Graphics 对象使用当前绘制位置作为第一个锚点。调用 curveTo() 方法时,将传递以下四个参数:控制点的 x 和 y 坐标, 后跟第二个锚点的 x 和 y 坐标。例如,以下代码绘制一条曲线,它从点 (100, 100) 开始,到点 (200, 200) 结束。由于控制点位 于点 (175, 125),因此,这会创建一条曲线,它先向右移动,然后向下移动:188ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 myShape.graphics.moveTo(100, 100); myShape.graphics.curveTo(175, 125, 200, 200); 以下示例绘制红色和绿色圆形对象,其宽度和高度均为 100 个像素。请注意,由于二次贝塞尔方程式所具有的特性,这些对象 并不是完美的圆: var size:uint = 100; var roundObject:Shape = new Shape(); // red circular shape roundObject.graphics.beginFill(0xFF0000); roundObject.graphics.moveTo(size / 2, 0); roundObject.graphics.curveTo(size, 0, size, size / 2); roundObject.graphics.curveTo(size, size, size / 2, size); roundObject.graphics.curveTo(0, size, 0, size / 2); roundObject.graphics.curveTo(0, 0, size / 2, 0); // green circular shape roundObject.graphics.beginFill(0x00FF00); roundObject.graphics.moveTo(200 + size / 2, 0); roundObject.graphics.curveTo(200 + size, 0, 200 + size, size / 2); roundObject.graphics.curveTo(200 + size, size, 200 + size / 2, size); roundObject.graphics.curveTo(200, size, 200, size / 2); roundObject.graphics.curveTo(200, 0, 200 + size / 2, 0); this.addChild(roundObject); 使用内置方法绘制形状 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 为了便于绘制常见形状 (如圆、椭圆、矩形以及带圆角的矩形), ActionScript 3.0 中提供了用于绘制这些常见形状的方法。 它们是 Graphics 类的 drawCircle()、 drawEllipse()、 drawRect() 和 drawRoundRect() 方法。这些方法可用于替代 lineTo() 和 curveTo() 方法。但要注意,在调用这些方法之前,您仍需指定线条和填充样式。 以下示例重新创建绘制红色、绿色以及蓝色正方形的示例,其宽度和高度均为 100 个像素。以下代码使用 drawRect() 方法,并 且还指定了填充颜色的 Alpha 为 50% (0.5): var squareSize:uint = 100; var square:Shape = new Shape(); square.graphics.beginFill(0xFF0000, 0.5); square.graphics.drawRect(0, 0, squareSize, squareSize); square.graphics.beginFill(0x00FF00, 0.5); square.graphics.drawRect(200, 0, squareSize, squareSize); square.graphics.beginFill(0x0000FF, 0.5); square.graphics.drawRect(400, 0, squareSize, squareSize); square.graphics.endFill(); this.addChild(square); 在 Sprite 或 MovieClip 对象中,使用 graphics 属性创建的绘制内容始终出现在该对象包含的所有子级显示对象的后面。另外, graphics 属性内容不是单独的显示对象,因此,它不会出现在 Sprite 或 MovieClip 对象的子级列表中。例如,以下 Sprite 对 象使用其 graphics 属性来绘制圆,并且其子级显示对象列表中包含一个 TextField 对象:189ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 var mySprite:Sprite = new Sprite(); mySprite.graphics.beginFill(0xFFCC00); mySprite.graphics.drawCircle(30, 30, 30); var label:TextField = new TextField(); label.width = 200; label.text = "They call me mellow yellow..."; label.x = 20; label.y = 20; mySprite.addChild(label); this.addChild(mySprite); 请注意, TextField 将出现在使用 graphics 对象绘制的圆的上面。 创建渐变线条和填充 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 graphics 对象也可以绘制渐变笔触和填充,而不是纯色笔触和填充。渐变笔触是使用 lineGradientStyle() 方法创建的;渐变填 充是使用 beginGradientFill() 方法创建的。 这两种方法接受相同的参数。前四个参数是必需的,即类型、颜色、 Alpha 以及比率。其余四个参数是可选的,但对于高级自 定义非常有用。 • 第一个参数指定要创建的渐变类型。可接受的值为 GradientType.LINEAR 或 GradientType.RADIAL。 • 第二个参数指定要使用的颜色值的数组。在线性渐变中,将从左向右排列颜色。在放射状渐变中,将从内到外排列颜色。数 组颜色的顺序表示在渐变中绘制颜色的顺序。 • 第三个参数指定前一个参数中相应颜色的 Alpha 透明度值。 • 第四个参数指定比率或每种颜色在渐变中的重要程度。可接受的值范围是 0-255。这些值并不表示任何宽度或高度,而是表 示在渐变中的位置; 0 表示渐变开始,255 表示渐变结束。比率数组必须按顺序增加,并且包含的条目数与第二个和第三个 参数中指定的颜色和 Alpha 数组相同。 虽然第五个参数 (转换矩阵)是可选的,但通常会使用该参数,因为它提供了一种简便且有效的方法来控制渐变外观。此参数 接受 Matrix 实例。为渐变创建 Matrix 对象的最简单方法是使用 Matrix 类的 createGradientBox() 方法。 定义 Matrix 对象以用于渐变 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可以使用 flash.display.Graphics 类的 beginGradientFill() 和 lineGradientStyle() 方法来定义在形状中使用的渐变。定义渐变 时,需要提供一个矩阵作为这些方法的其中一个参数。 定义矩阵的最简单方法是使用 Matrix 类的 createGradientBox() 方法,该方法创建一个用于定义渐变的矩阵。可以使用传递给 createGradientBox() 方法的参数来定义渐变的缩放、旋转和位置。 createGradientBox() 方法接受以下参数: • 渐变框宽度:渐变扩展到的宽度 (以像素为单位) • 渐变框高度:渐变扩展到的高度 (以像素为单位) • 渐变框旋转:将应用于渐变的旋转角度 (以弧度为单位) • 水平平移:将渐变水平移动的距离 (以像素为单位) • 垂直平移:将渐变垂直移动的距离 (以像素为单位)190ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 例如,假设渐变具有以下特性: • GradientType.LINEAR • 绿色和蓝色这两种颜色 (ratios 数组设置为 [0, 255]) • SpreadMethod.PAD • InterpolationMethod.LINEAR_RGB 下面的示例显示的是几种渐变,如图所示,它们的 createGradientBox() 方法的 rotation 参数不同,但所有其他设置是相同的: 下面的示例显示的是绿到蓝线性渐变的效果,如图所示,它们的 createGradientBox() 方法的 rotation、 tx 和 ty 参数不同,但所 有其他设置是相同的: width = 100; height = 100; rotation = 0; tx = 0; ty = 0; width = 100; height = 100; rotation = Math.PI/4; // 45° tx = 0; ty = 0; width = 100; height = 100; rotation = Math.PI/2; // 90° tx = 0; ty = 0; 191ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 createGradientBox() 方法的 width、 height、 tx 和 ty 参数也会影响 “ 放射状 ” 渐变填充的大小和位置,如下面的示例所示: 下面的代码生成了所示的最后一个放射状渐变: width = 50; height = 100; rotation = 0; tx = 0; ty = 0; width = 50; height = 100; rotation = 0 tx = 50; ty = 0; width = 100; height = 50; rotation = Math.PI/2; // 90° tx = 0; ty = 0; width = 100; height = 50; rotation = Math.PI/2; // 90° tx = 0; ty = 50; width = 50; height = 100; rotation = 0; tx = 25; ty = 0; 192ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 import flash.display.Shape; import flash.display.GradientType; import flash.geom.Matrix; var type:String = GradientType.RADIAL; var colors:Array = [0x00FF00, 0x000088]; var alphas:Array = [1, 1]; var ratios:Array = [0, 255]; var spreadMethod:String = SpreadMethod.PAD; var interp:String = InterpolationMethod.LINEAR_RGB; var focalPtRatio:Number = 0; var matrix:Matrix = new Matrix(); var boxWidth:Number = 50; var boxHeight:Number = 100; var boxRotation:Number = Math.PI/2; // 90° var tx:Number = 25; var ty:Number = 0; matrix.createGradientBox(boxWidth, boxHeight, boxRotation, tx, ty); var square:Shape = new Shape; square.graphics.beginGradientFill(type, colors, alphas, ratios, matrix, spreadMethod, interp, focalPtRatio); square.graphics.drawRect(0, 0, 100, 100); addChild(square); 请注意,渐变填充的宽度和高度是由渐变矩阵的宽度和高度决定的,而不是由使用 Graphics 对象绘制的宽度和高度决定的。 使用 Graphics 对象进行绘制时,您绘制的内容位于渐变矩阵中的这些坐标处。即使使用 Graphics 对象的形状方法之一 (如 drawRect()),渐变也不会将其自身伸展到绘制的形状的大小;必须在渐变矩阵本身中指定渐变的大小。 下面说明了渐变矩阵的尺寸和绘图本身的尺寸之间的视觉差异: var myShape:Shape = new Shape(); var gradientBoxMatrix:Matrix = new Matrix(); gradientBoxMatrix.createGradientBox(100, 40, 0, 0, 0); myShape.graphics.beginGradientFill(GradientType.LINEAR, [0xFF0000, 0x00FF00, 0x0000FF], [1, 1, 1], [0, 128, 255], gradientBoxMatrix); myShape.graphics.drawRect(0, 0, 50, 40); myShape.graphics.drawRect(0, 50, 100, 40); myShape.graphics.drawRect(0, 100, 150, 40); myShape.graphics.endFill(); this.addChild(myShape); 该代码绘制三个具有相同填充样式 (使用平均分布的红色、绿色和蓝色指定的)的渐变。这些渐变是使用 drawRect() 方法绘制 的,像素宽度分别为 50、 100 和 150。 beginGradientFill() 方法中指定的渐变矩阵是使用像素宽度 100 创建的。这意味着,第 一个渐变仅包含渐变色谱的一半,第二个渐变包含全部色谱,而第三个渐变包含全部色谱以及向右扩展的额外 50 蓝色像素。 lineGradientStyle() 方法的工作方式与 beginGradientFill() 类似,所不同的是,除了定义渐变外,您还必须在绘制之前使用 lineStyle() 方法指定笔触粗细。以下代码绘制一个带有红色、绿色和蓝色渐变笔触的框:193ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 var myShape:Shape = new Shape(); var gradientBoxMatrix:Matrix = new Matrix(); gradientBoxMatrix.createGradientBox(200, 40, 0, 0, 0); myShape.graphics.lineStyle(5, 0); myShape.graphics.lineGradientStyle(GradientType.LINEAR, [0xFF0000, 0x00FF00, 0x0000FF], [1, 1, 1], [0, 128, 255], gradientBoxMatrix); myShape.graphics.drawRect(0, 0, 200, 40); this.addChild(myShape); 有关 Matrix 类的详细信息,请参阅第 180 页的 “ 使用 Matrix 对象 ”。 将 Math 类与绘制方法配合使用 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Graphics 对象可以绘制圆和正方形,但也可以绘制更复杂的形状,尤其是在将绘制方法与 Math 类的属性和方法配合使用时。 Math 类包含人们通常很感兴趣的数学常量,如 Math.PI (约等于 3.14159265...),此常量表示圆的周长与其直径的比率。它 还包含三角函数的方法,其中包括 Math.sin()、Math.cos() 和 Math.tan() 等。使用这些方法和常量绘制形状可产生更动态的视觉 效果,尤其是用于重复或递归时。 Math 类的很多方法都要求以弧度为单位来测量圆弧,而不是使用角度。 Math 类的一个常见用途是在这两种类型的单位之间 进行转换: var degrees = 121; var radians = degrees * Math.PI / 180; trace(radians) // 2.111848394913139 以下示例创建一个正弦波和余弦波以重点说明给定值的 Math.sin() 和 Math.cos() 方法之间的差异。 var sinWavePosition = 100; var cosWavePosition = 200; var sinWaveColor:uint = 0xFF0000; var cosWaveColor:uint = 0x00FF00; var waveMultiplier:Number = 10; var waveStretcher:Number = 5; var i:uint; for(i = 1; i < stage.stageWidth; i++) { var sinPosY:Number = Math.sin(i / waveStretcher) * waveMultiplier; var cosPosY:Number = Math.cos(i / waveStretcher) * waveMultiplier; graphics.beginFill(sinWaveColor); graphics.drawRect(i, sinWavePosition + sinPosY, 2, 2); graphics.beginFill(cosWaveColor); graphics.drawRect(i, cosWavePosition + cosPosY, 2, 2); } 使用绘图 API 进行动画处理 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用绘图 API 创建内容的一个优点是,您并不限于将内容放置一次。可通过保留和修改用于绘制的变量来修改所绘制的内容。 您可以通过更改变量和重绘 (在一段帧上或使用计时器)来利用原有的动画。194ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 例如,以下代码更改每个经过的帧 (通过侦听 Event.ENTER_FRAME 事件)的显示内容以增加当前度数,指示 graphics 对象 清除内容并在更新位置进行重绘。 stage.frameRate = 31; var currentDegrees:Number = 0; var radius:Number = 40; var satelliteRadius:Number = 6; var container:Sprite = new Sprite(); container.x = stage.stageWidth / 2; container.y = stage.stageHeight / 2; addChild(container); var satellite:Shape = new Shape(); container.addChild(satellite); addEventListener(Event.ENTER_FRAME, doEveryFrame); function doEveryFrame(event:Event):void { currentDegrees += 4; var radians:Number = getRadians(currentDegrees); var posX:Number = Math.sin(radians) * radius; var posY:Number = Math.cos(radians) * radius; satellite.graphics.clear(); satellite.graphics.beginFill(0); satellite.graphics.drawCircle(posX, posY, satelliteRadius); } function getRadians(degrees:Number):Number { return degrees * Math.PI / 180; } 要产生明显不同的效果,您可以尝试修改代码开头的初始种子变量 (currentDegrees、 radius 和 satelliteRadius)。例如,尝试 缩小 radius 变量和 / 或增大 totalSatellites 变量。这只是一个说明绘图 API 如何创建可视显示内容(其复杂性掩盖了创建简便 性)的示例。 绘制 API 示例:算法可视化生成器 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Algorithmic Visual Generator 示例在舞台上动态绘制几个 “ 卫星 ”,即在圆形轨道中运动的圆形物。要阐述的功能包括: • 使用绘图 API 绘制具有动态外观的基本形状 • 将用户交互与绘图中使用的属性相关联 • 清除每个帧中的舞台内容并重绘以利用原有的动画 上一小节中的示例使用 Event.ENTER_FRAME 事件对唯一的 “ 卫星 ” 进行动画处理。该示例在此基础之上进一步扩展,生成一 个包含一系列滑块的控制面板,这些滑块会立即更新若干卫星的可视显示内容。此示例将代码格式设置为外部类,并将卫星创 建代码包装在循环中,以将对每个卫星的引用存储在 satellites 数组中。 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在 Samples/AlgorithmicVisualGenerator 文件夹中找到应用程序文件。此文件夹包含以下文件:195ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 设置侦听器 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 应用程序先创建三个侦听器。第一个侦听器侦听从控制面板中调度的事件:必须对卫星进行重新构建。第二个侦听器侦听对 SWF 文件的舞台大小的更改。第三个侦听器侦听 SWF 文件中每个经过的帧,并使用 doEveryFrame() 函数进行重绘。 创建卫星 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在设置这些侦听器后,将调用 build() 函数。此函数先调用 clear() 函数,后者清空 satellites 数组,并清除以前在舞台上绘制的任 何内容。这是必要的,因为每当控制面板发送事件来执行此操作时,都可能会重新调用 build() 函数,例如在颜色设置已发生变 化时。在这种情况下,必须删除并重新创建卫星。 该函数随后创建一些卫星,并设置创建所需的初始属性,如 position 变量 (从轨道中的随机位置开始)和 color 变量 (在本示 例中,该变量在创建卫星后不会发生改变)。 创建每个卫星时,会将对它的引用添加到 satellites 数组中。调用 doEveryFrame() 函数时,它将更新此数组中的所有卫星。 更新卫星位置 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 doEveryFrame() 函数是应用程序动画过程的核心。将为每个帧调用该函数,频率等于 SWF 文件的帧频。由于绘制变量略微发 生了变化,因此,这会利用原有的动画外观。 该函数先清除以前绘制的所有内容,然后再重绘背景。接下来,它循环访问每个卫星容器,增加每个卫星的 position 属性以及 更新 radius 和 orbitRadius 属性 (这些属性可能由于用户与控制面板的交互而发生了变化)。最后,通过调用 Satellite 类的 draw() 方法,在新位置对卫星进行更新。 请注意,计数器 i 最多只增加到 visibleSatellites 变量。这是因为,如果用户通过控制面板限制了显示的卫星数,则不会重绘循环 中的其余卫星,而应将其隐藏起来。这种情况发生在紧靠负责绘制的循环后面的循环中。 当 doEveryFrame() 函数完成时,将在屏幕上的位置中更新 visibleSatellites 数量。 文件 说明 AlgorithmicVisualGenerator.fla Flash Professional 中的主应用程序文件 (FLA)。 com/example/programmingas3/algorithmic/AlgorithmicVisualGenerator.as 此类提供应用程序的主要功能,其中包括在舞台上绘制卫 星,以及从控制面板中响应事件以更新影响卫星绘制的变 量。 com/example/programmingas3/algorithmic/ControlPanel.as 此类管理用户与几个滑块之间的交互并在发生此类交互时 调度事件。 com/example/programmingas3/algorithmic/Satellite.as 此类表示在轨道中围绕中心点旋转的显示对象,并包含与 其当前绘制状态有关的属性。196ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 响应用户交互 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 用户交互是通过控制面板发生的,它是由 ControlPanel 类管理的。此类设置一个侦听器,并为每个滑块设置单独的最小、最 大和默认值。当用户移动这些滑块时,将调用 changeSetting() 函数。此函数更新控制面板的属性。如果更改需要重新构建显示 内容,则会调度一个事件,随后将在主应用程序文件中对该事件进行处理。当控制面板设置发生变化时, doEveryFrame() 函数 将使用更新的变量绘制每个卫星。 进一步自定义 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 本示例只是概要介绍了使用绘图 API 生成可视内容方面的基础知识。它使用相对较少的几行代码来创建似乎非常复杂的交互式 体验。尽管如此,您还是可以对本示例进行较小的改动以进行扩展。下面列出了一些很好的方法: • doEveryFrame() 函数可以增加卫星的颜色值。 • doEveryFrame() 函数可能会随着时间的推移缩小或增大卫星半径。 • 卫星并不一定是圆形的,例如,可以使用 Math 类根据正弦波来移动其半径。 • 卫星可以使用碰撞检测来检查是否与其他卫星重叠。 可以将绘图 API 作为在 Flash 创作环境中创建视觉效果的替代方法,以便在运行时绘制基本形状。但是,它也可以用来创建涵 盖范围很广且无法手动创建的各种视觉效果。通过使用绘图 API 和一些数学函数, ActionScript 作者可能实现很多意想不到 的创作效果。 绘图 API 高级用法 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 Flash Player 10 运行时、Adobe AIR 1.5 运行时和更高版本的 Flash 运行时支持一组高级绘图功能。这些运行时的绘图 API 增强功能对早期版本中的绘图方法进行了扩展,使您通过建立数据集,即可生成形状、在运行时更改形状及创建三维效果。绘 图 API 增强功能将现有方法合并为其他命令。这些命令利用矢量数组和枚举类为绘图方法提供数据集。使用矢量数组,可以快 速呈示更复杂的形状,开发人员可以用编程方式为运行时呈示的动态形状更改数组值。 下面几节介绍 Flash Player 10 中引入的绘制功能:第 197 页的 “ 绘制路径 ”、第 198 页的 “ 定义缠绕规则 ”、第 200 页的 “ 使用图形数据类 ” 和第 202 页的 “ 关于使用 drawTriangles()”。 您可能需要使用 ActionScript 中的高级绘图 API 来完成以下任务: • 使用 Vector 对象存储绘制方法的数据 • 以编程方式定义用于绘制形状的路径 (用单个操作) • 定义缠绕规则,以确定如何填充重叠形状 • 读取显示对象的矢量图形内容,如序列化并保存图形数据、在运行时生成 Sprite 表以及绘制矢量图形内容的副本 • 使用三角形和绘制方法实现三维效果197ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 重要概念和术语 以下参考列表包含本节中会遇到的重要术语: • 矢量:数据类型完全相同的值组成的数组。 Vector 对象可存储绘制方法使用单个命令构建线条和形状时所用值的数组。有 关 Vector 对象的详细信息,请参阅第 22 页的 “ 索引数组 ”。 • 路径:路径由一条或多条直线段或曲线段组成。每个线段的起点和终点都由坐标标记,就像用于固定线的针。路径可以是闭 合的,例如圆;也可以是开放的,且具有不同的端点,例如波浪线。 • 缠绕:由渲染器解释的路径方向,包括正向 (顺时针)或负向 (逆时针)。 • GraphicsStroke:用于设置线条样式的类。虽然 “ 笔触 ” 并非绘图 API 增强功能中的术语,但使用类以线条样式自身的填充 属性来指定该线条样式却是新绘图 API 功能的一部分。您可以使用 GraphicsStroke 类动态调整线条的样式。 • Fill 对象:使用 flash.display.GraphicsBitmapFill 和 flash.display.GraphicsGradientFill 等传递给绘图命令 Graphics.drawGraphicsData() 的显示类所创建的对象。 Fill 对象和增强的绘图命令引入了一种面向对象程度更高的编程方 法,用于复现 Graphics.beginBitmapFill() 和 Graphics.beginGradientFill() 的效果。 绘制路径 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 有关绘制线条和曲线的节中 (请参阅第 186 页的 “ 绘制线条和曲线 ”)介绍了一些命令,它们可用于绘制单个线条 (Graphics.lineTo()) 或曲线 (Graphics.curveTo()),然后将得到的线移至另一点 (Graphics.moveTo()),从而组成形状。 Graphics.drawPath() 和 Graphics.drawTriangles() 方法接受一组对象,它们将那些相同的绘图命令表示为一个参数。使用这些方 法,您可以提供一系列 Graphics.lineTo()、Graphics.curveTo()、Graphics.moveTo() 命令,使 Flash 运行时在一个单独的语句中 执行这些命令。 GraphicsPathCommand 枚举类定义一组对应于绘图命令的常量。您可以将这一系列常量 (包装在 Vector 实例中)作为对 Graphics.drawPath() 方法的一个参数来传递,然后通过一个单独的命令便可以呈现整个形状或多个形状。您还可以更改传递给 这些方法的值,以更改现有形状。 除了这个绘图命令 Vector 之外,drawPath() 方法还需要一组坐标来对应每个绘图命令的坐标。创建一个包含坐标的 Vector 实 例(Number 实例),将其作为第二个参数 (data) 传递给 drawPath() 方法。 注: 矢量中的值不是 Point 对象;该矢量是一系列数字,其中由两个数字组成的每个组表示一个 x/y 坐标对。 Graphics.drawPath() 方法将每个命令与其各自的点值 (由两个或四个数字组成的集合)相匹配,以在 Graphics 对象中生成路 径:198ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 package { import flash.display.*; public class DrawPathExample extends Sprite { public function DrawPathExample(){ var squareCommands:Vector. = new Vector.(5, true); squareCommands[0] = GraphicsPathCommand.MOVE_TO; squareCommands[1] = GraphicsPathCommand.LINE_TO; squareCommands[2] = GraphicsPathCommand.LINE_TO; squareCommands[3] = GraphicsPathCommand.LINE_TO; squareCommands[4] = GraphicsPathCommand.LINE_TO; var squareCoord:Vector. = new Vector.(10, true); squareCoord[0] = 20; //x squareCoord[1] = 10; //y squareCoord[2] = 50; squareCoord[3] = 10; squareCoord[4] = 50; squareCoord[5] = 40; squareCoord[6] = 20; squareCoord[7] = 40; squareCoord[8] = 20; squareCoord[9] = 10; graphics.beginFill(0x442266);//set the color graphics.drawPath(squareCommands, squareCoord); } } } 定义缠绕规则 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 增强的绘图 API 还引入了路径 “ 缠绕 ” 的概念:路径的方向。路径的缠绕可以是正向的 (顺时针),也可以是负向的(逆时 针)。渲染器为 data 参数解释矢量所提供坐标的顺序确定了缠绕的方向。 正向缠绕和负向缠绕 A. 指示绘制方向的箭头 B. 正向缠绕 (顺时针) C. 负向缠绕 (逆时针) 此外,请注意 Graphics.drawPath() 方法可选的第三个参数 “winding”: drawPath(commands:Vector., data:Vector., winding:String = "evenOdd"):void B 1 23 0 12 30 C A199ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 在这种情况下,第三个参数是一个字符串或常量,用于指定相交路径的缠绕或填充规则。(这些常量值在 GraphicsPathWinding 类中定义为 GraphicsPathWinding.EVEN_ODD 或 GraphicsPathWinding.NON_ZERO。)当路径相交 时,缠绕规则十分重要。 奇偶规则是标准的缠绕规则,早期的绘图 API 都使用此规则。奇偶规则也是 Graphics.drawPath() 方法的默认规则。使用奇偶 缠绕规则时,任何相交路径都交替使用开放填充与闭合填充。如果使用同一填充绘制的两个正方形相交,则不会填充相交的区 域。通常,相邻区域不会都填充或都不填充。 另一方面,非零规则依靠缠绕 (绘制方向)来确定是否填充相交路径定义的区域。当相对缠绕的路径相交时,不填充所定义的 区域,这与奇偶规则十分类似。对于相同缠绕的路径,将填充本来不填充的区域: 用于相交区域的缠绕规则 A. 奇偶缠绕规则 B. 非零缠绕规则 缠绕规则名称 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 这些名称系指用于定义如何管理填充的更具体规则。正向缠绕路径将得到赋值 +1 ;负向缠绕路径将得到赋值 -1。以形状上闭 合区域中的一点为起点,绘制一个从该点向外无限延伸的线条。使用该线条与路径相交的次数以及这些路径的组合值来确定填 充。对于奇偶缠绕,使用该线条与路径相交的次数。如果计数为奇数,则填充相交区域。如果计数为偶数,则不填充相交区 域。对于非零缠绕,使用赋予路径的值。如果路径的组合值不为 0,则填充相交区域。如果组合值为 0,则不填充相交区域。 缠绕规则计数和填充 A. 奇偶缠绕规则 B. 非零缠绕规则 使用缠绕规则 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 这些填充规则很复杂,但有些情况下必须使用它们。例如绘制星形时。如果使用标准奇偶规则,该形状需要十个不同的线条。 如果使用非零缠绕规则,所需十个线条将减少为五个。下面的 ActionScript 使用五个线条和非零缠绕规则来绘制星形: AB AB200ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 graphics.beginFill(0x60A0FF); graphics.drawPath( Vector.([1,2,2,2,2]), Vector.([66,10, 23,127, 122,50, 10,49, 109,127]), GraphicsPathWinding.NON_ZERO); 星形如下所示: 使用不同缠绕规则的星形 A. 奇偶 10 个线条 B. 奇偶 5 个线条 C. 非零 5 个线条 如果对图像进行了动画处理,或图像用作三维对象上的纹理且发生重叠,则缠绕规则会变得更为重要。 使用图形数据类 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 增强的绘图 API 包括 flash.display 包中用于实现 IGraphicsData 接口的一组类。这些类用作表示绘图 API 的绘图方法的值 对象 (数据容器)。 下面的类实现 IGraphicsData 接口: • GraphicsBitmapFill • GraphicsEndFill • GraphicsGradientFill • GraphicsPath • GraphicsShaderFill • GraphicsSolidFill • GraphicsStroke • GraphicsTrianglePath 通过这些类,可以将一个完整的绘图存储在一个 IGraphicsData 类型的 Vector 对象 (Vector.) 中。之后您 可以重新利用这些图形数据作为其他形状实例的数据源或存储绘图信息供以后使用。 请注意,每个填充样式有多个填充类,但只有一个笔触类。 ActionScript 只有一个笔触类 IGraphicsData,因为该笔触类使 用填充类来定义自己的样式。因此每个笔触实际上是由一个笔触类和一个填充类的组合定义的。否则,这些图形数据类的 API 会镜像它们在 flash.display.Graphics 类中表示的方法: Graphics 方法 对应的类 beginBitmapFill() GraphicsBitmapFill beginFill() GraphicsSolidFill beginGradientFill() GraphicsGradientFill beginShaderFill() GraphicsShaderFill lineBitmapStyle() GraphicsStroke + GraphicsBitmapFill A B C201ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 此外, GraphicsPath 类拥有自己的 GraphicsPath.moveTo()、 GraphicsPath.lineTo()、 GraphicsPath.curveTo()、 GraphicsPath.wideLineTo() 和 GraphicsPath.wideMoveTo() 实用程序方法,用于轻松为 GraphicsPath 实例定义这些命令。这 些实用程序方法简化了直接定义或更新这些命令和数据值的过程。 使用矢量图形数据绘图 有了 IGraphicsData 实例集合之后,便可使用 Graphics 类的 drawGraphicsData() 方法来呈现图形了。drawGraphicsData() 方 法将按顺序执行 IGraphicsData 实例矢量中的一组绘图指令: // stroke object var stroke:GraphicsStroke = new GraphicsStroke(3); stroke.joints = JointStyle.MITER; stroke.fill = new GraphicsSolidFill(0x102020);// solid stroke // fill object var fill:GraphicsGradientFill = new GraphicsGradientFill(); fill.colors = [0x0000FF, 0xEEFFEE]; fill.matrix = new Matrix(); fill.matrix.createGradientBox(70, 70, Math.PI/2); // path object var path:GraphicsPath = new GraphicsPath(new Vector.(), new Vector.()); path.commands.push(GraphicsPathCommand.MOVE_TO, GraphicsPathCommand.LINE_TO, GraphicsPathCommand.LINE_TO); path.data.push(125,0, 50,100, 175,0); // combine objects for complete drawing var drawing:Vector. = new Vector.(); drawing.push(stroke, fill, path); // draw the drawing graphics.drawGraphicsData(drawing); 通过修改示例中绘制所用路径的一个值,可以多次重绘形状,以生成更复杂的图像: // draw the drawing multiple times // change one value to modify each variation graphics.drawGraphicsData(drawing); path.data[2] += 200; graphics.drawGraphicsData(drawing); path.data[2] -= 150; graphics.drawGraphicsData(drawing); path.data[2] += 100; graphics.drawGraphicsData(drawing); path.data[2] -= 50;graphicsS.drawGraphicsData(drawing); lineGradientStyle() GraphicsStroke + GraphicsGradientFill lineShaderStyle() GraphicsStroke + GraphicsShaderFill lineStyle() GraphicsStroke + GraphicsSolidFill moveTo() lineTo() curveTo() drawPath() GraphicsPath drawTriangles() GraphicsTrianglePath Graphics 方法 对应的类202ACTIONSCRIPT 3.0 开发人员指南 使用绘图 API 上次更新 2014/12/1 尽管 IGraphicsData 对象可以定义填充和笔触样式,但这两种样式并不是必需的。换句话说,可以在使用 IGraphicsData 对 象绘制已保存路径集合的同时,使用 Graphics 类方法设置样式,反之亦然。 注: 开始新的绘制之前,请使用 Graphics.clear() 方法清除以前的绘制;除非如上例所示,要在原始绘制的基础上继续绘制。在 更改路径或 IGraphicsData 对象集合的某个部分时,请重绘整个绘制来查看所做的更改。 使用图形数据类时,只要绘制了三点或更多点,就会呈示填充,这是因为形状实际上在该点闭合。即使填充闭合,笔触也不会 闭合;这一行为与使用多个 Graphics.lineTo() 或 Graphics.moveTo() 命令时不同。 读取矢量图形数据 Flash Player 11.6 和更高版本, Adobe AIR 3.6 和更高版本 除了将矢量内容绘制到显示对象之外,在 Flash Player 11.6 和 Adobe AIR 3.6 及更高版本中,您还可以使用 Graphics 类的 readGraphicsData() 方法来获取显示对象的矢量图形内容的数据表示。这可以用于创建一个图形快照以便在运行时保存、复制、 创建 Sprite 表等等。 调用 readGraphicsData() 方法将返回一个包含 IGraphicsData 对象的 Vector 实例。这些对象就是使用 drawGraphicsData() 方 法绘制矢量图形所用的对象。 使用 readGraphicsData() 方法读取矢量图形存在一些限制。有关详细信息,请参阅 《ActionScript 语言参考》中的 readGraphicsData() 条目。 关于使用 drawTriangles() Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 Graphics.drawTriangles() 是 Flash Player 10 和 Adobe AIR 1.5 中引进的另一种高级方法,与 Graphics.drawPath() 方法相似。 Graphics.drawTriangles() 方法还使用 Vector. 对象指定用于绘制路径的点位置。 但是, Graphics.drawTriangles() 方法的实际作用是便于通过 ActionScript 实现三维效果。有关使用 Graphics.drawTriangles() 生成三维效果的信息,请参阅第 304 页的 “ 通过三角形获得 3D 效果 ”。203 上次更新 2014/12/1 第 13 章 : 使用位图 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 除了矢量图功能以外, ActionScript 3.0 还提供创建位图图像或操作加载到 SWF 中的外部位图图像的像素数据的功能。使用 访问和更改各个像素值的功能,您可以创建自己的滤镜式图像效果并使用内置杂点功能创建纹理和随机杂点。 • Renaun Erickson:在 ActionScript 中,采用块传输技术渲染游戏资源 • 位图编程:Colin Moock 编著的 《Essential ActionScript 3》的第 26 章(2007 年由 O'Reilly Media 出版) • Mike Jones:在 Pushbutton 引擎中使用贴图定位 • Flash & Math:简单制作粒子像素系统 • Flixel 位图使用基本知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用数字图像时,您可能会遇到两种主要的图形类型:位图和矢量图形。位图图形也称为光栅图形,由排列为矩形网格形式的 小方块 (像素)组成。矢量图形由以数学方式生成的几何形状 (如直线、曲线和多边形)组成。 位图图像用图像的宽度和高度来定义,以像素为量度单位,每个像素包含的位数表示像素包含的颜色数。在使用 RGB 颜色模 型的位图图像中,像素由三个字节组成:红、绿和蓝。每个字节包含一个 0 至 255 之间的值。将字节与像素合并时,它们可以 产生与艺术混合绘画颜色相似的颜色。例如,一个包含红色字节值 255、绿色字节值 102 和蓝色字节值 0 的像素可以形成明快 的橙色。 位图图像的品质由图像分辨率和颜色深度位值共同确定。分辨率与图像中包含的像素数有关。像素数越大,分辨率越高,图像 也就越精确。颜色深度与像素可包含的信息量有关。例如,颜色深度值为每像素 16 位的图像无法显示颜色深度为 48 位的图像 所具有颜色数。因此, 48 位图像与 16 位图像相比,其阴影具有更高的平滑度。 由于位图图形与分辨率有关,因此不能很好地进行缩放。当放大位图图像时,这一特性显得尤为突出。通常,放大位图有损其 细节和品质。 位图文件格式 位图图像可分为几种常见的文件格式。这些格式使用不同类型的压缩算法减小文件大小,并基于图像的最终用途优化图像品 质。 Adobe 运行时支持的位图图像格式包括 BMP、 GIF、 JPG、 PNG 和 TIFF。 BMP BMP (位映射)格式是 Microsoft Windows 操作系统使用的默认图像格式。这种格式不使用任何形式的压缩算法,因此文 件大小通常较大。 GIF 图形交换格式 (GIF) 最初由 CompuServe 于 1987 年开发,作为一种传送 256 色(8 位颜色)图像的方式。此格式提供较小 的文件大小,是基于 Web 的图像的理想格式。受此格式的调色板所限, GIF 图像通常不适用于照片,照片通常需要高度的阴 影和颜色渐变。 GIF 图像允许产生一位透明度,允许将颜色映射为清晰 (或透明)。这可以使网页的背景颜色通过已映射透明 度的图像显示出来。204ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 JPEG 由联合图像专家组 (JPEG) 开发, JPEG (通常写成 JPG)图像格式使用有损压缩算法允许 24 位颜色深度具有很小的文件大 小。有损压缩意味着每次保存图像,都会损失图像品质和数据,但会生成更小的文件大小。由于 JPEG 能够显示数百万计的颜 色,因此它是照片的理想格式。控制应用于图像的压缩程度的功能使您能够控制图像品质和文件大小。 PNG 可移植网络图形 (PNG) 格式是作为受专利保护的 GIF 文件格式的开放源替代格式而开发的。PNG 最多支持 64 位颜色深度, 允许使用最多 1600 万种颜色。由于 PNG 是一种比较新的格式,因此一些旧版本浏览器不支持 PNG 文件。与 JPG 不同, PNG 使用无损压缩,这意味着保存图像时不会丢失图像数据。PNG 文件还支持 Alpha 透明度,允许使用最多 256 级透明度。 TIFF 标签图像文件格式 (TIFF) 是在引入 PNG 之前的首选跨平台格式。 TIFF 格式的缺点是,因为 TIFF 有多种不同变体,但没有 一种阅读器能够处理所有版本。此外,所有 Web 浏览器当前均不支持这种格式。TIFF 可以使用有损或无损压缩,能够处理特 定于设备的颜色空间 (如 CMYK)。 透明位图和不透明位图 使用 GIF 或 PNG 格式的位图图像可以对每个像素添加一个额外字节 (Alpha 通道)。此额外像素字节表示像素的透明度值。 GIF 图像允许使用一位透明度,这意味着您可以在 256 色调色板中指定一种透明的颜色。而 PNG 图像最多可以有 256 级透明 度。当需要将图像或文本混合到背景中时,此功能特别有用。 ActionScript 3.0 在 BitmapData 类中复制了此额外透明度像素字节。与 PNG 透明度模型类似,ActionScript 最多提供 256 级透明度。 重要概念和术语 以下列表中包括您了解位图图形时会遇到的重要术语。 Alpha 颜色或图像中的透明度级别 (更准确地说是指不透明度)。 Alpha 量通常称为 “Alpha 通道 ” 值。 ARGB 颜色 一种配色方案,其中每个像素的颜色都是红、绿和蓝色值的混合颜色,并且其透明度被指定为一个 Alpha 值。 颜色通道 通常将颜色表示为几种基本颜色的混合颜色;对于计算机图形来说,基本颜色通常是红色、绿色和蓝色。每种基本颜 色都视为一个颜色通道;每个颜色通道中的颜色量混合在一起可确定最终颜色。 颜色深度 也称为 “ 位深度 ”,指专门用于每个像素的计算机内存量,因而可以确定图像中可以显示的可能颜色数。 像素 位图图像中的最小信息单位,实际上就是颜色点。 分辨率 图像的像素尺寸,它决定图像中包含的精细细节的级别。分辨率通常表示为用像素数表示的宽度和高度。 RGB 颜色 一种配色方案,其中每个像素的颜色均表示为红、绿和蓝色值的混合颜色。 Bitmap 和 BitmapData 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用位图图像的主要 ActionScript 3.0 类是 Bitmap 类和 BitmapData 类,前者用于在屏幕上显示位图图像,后者用于访问和 处理位图的原始图像数据。 更多帮助主题 flash.display.Bitmap flash.display.BitmapData205ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 了解 Bitmap 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 作为 DisplayObject 类的子类, Bitmap 类是用于显示位图图像的主要 ActionScript 3.0 类。这些图像可能已通过 flash.display.Loader 类加载或使用 Bitmap() 构造函数动态地创建。 从外部源加载图像时,Bitmap 对象只能使用 GIF、JPEG 或 PNG 格式的图像。实例化后,可将 Bitmap 实例视为需要呈示在舞台上的 BitmapData 对象的包装。由于 Bitmap 实例是 一个显示对象,因此可以使用显示对象的所有特性和功能来操作 Bitmap 实例。有关使用显示对象的详细信息,请参阅第 126 页的 “ 显示编程 ”。 像素贴紧和平滑 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 除了所有显示对象常见的功能外, Bitmap 类还提供了特定于位图图像的一些附加功能。 Bitmap 类的 pixelSnapping 属性可确定 Bitmap 对象是否贴紧最近的像素。此属性接受 PixelSnapping 类中定义的三个常量之 一:ALWAYS、 AUTO 和 NEVER。 应用像素贴紧的语法为: myBitmap.pixelSnapping = PixelSnapping.ALWAYS; 通常,缩放位图图像时,图像会变得模糊或扭曲。若要帮助减少这种扭曲,请使用 BitmapData 类的 smoothing 属性。如果将 该布尔值属性设置为 true,当缩放图像时,可使图像中的像素平滑或消除锯齿。它可使图像更加清晰、更加自然。 了解 BitmapData 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 BitmapData 类位于 flash.display 包中,它可以看作是加载的或动态创建的位图图像中包含的像素的照片快照。此快照用对象 中的像素数据的数组表示。 BitmapData 类还包含一系列内置方法,可用于创建和处理像素数据。 若要实例化 BitmapData 对象,请使用以下代码: var myBitmap:BitmapData = new BitmapData(width:Number, height:Number, transparent:Boolean, fillColor:uinit); width 和 height 参数指定位图的大小。从 AIR 3 和 Flash Player 11 开始,取消了 BitmapData 对象的大小限制。位图的最大 大小取决于操作系统。 在 AIR 1.5 和 Flash Player 10 中,BitmapData 对象的最大宽度或高度为 8,191 像素,并且像素总数不能超过 16,777,215 像 素。(因此,如果 BitmapData 对象的宽度为 8,191 像素,则其高度只能为 2,048 像素。)在 Flash Player 9 及早期版本和 AIR 1.1 及早期版本中,高度最大为 2,880 像素,宽度最大为 2,880 像素。 transparent 参数指定位图数据是 (true) 否 (false) 包括 Alpha 通道。fillColor 参数是一个 32 位颜色值,它指定背景颜色和透明 度值 (如果设置为 true)。以下示例创建一个具有 50% 透明的橙色背景的 BitmapData 对象: var myBitmap:BitmapData = new BitmapData(150, 150, true, 0x80FF3300); 若要在屏幕上呈示新创建的 BitmapData 对象,请将此对象分配给或包装到 Bitmap 实例中。为此,可以将 BitmapData 对象 作为 Bitmap 对象的构造函数参数传递,也可以将此对象分配给现有 Bitmap 实例的 bitmapData 属性。您还必须通过调用将包 含该 Bitmap 实例的显示对象容器的 addChild() 或 addChildAt() 方法将该 Bitmap 实例添加到显示列表中。有关使用显示列表 的详细信息,请参阅第 132 页的 “ 在显示列表中添加显示对象 ”。 以下示例创建一个具有红色填充的 BitmapData 对象,并在 Bitmap 实例中显示此对象:206ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 var myBitmapDataObject:BitmapData = new BitmapData(150, 150, false, 0xFF0000); var myImage:Bitmap = new Bitmap(myBitmapDataObject); addChild(myImage); 处理像素 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 BitmapData 类包含一组用于处理像素数据值的方法。 处理单个像素 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在像素级别更改位图图像的外观时,您首先需要获取要处理的区域中包含的像素的颜色值。使用 getPixel() 方法可读取这些像素 值。 getPixel() 方法从作为参数传递的一组 x, y (像素)坐标中检索 RGB 值。如果您要处理的像素包括透明度 (Alpha 通道)信 息,则需要使用 getPixel32() 方法。此方法也可以检索 RGB 值,但与 getPixel() 不同,getPixel32() 返回的值包含表示所选像素 的 Alpha 通道 (透明度)值的附加数据。 或者,如果只想更改位图中包含的某个像素的颜色或透明度,则可以使用 setPixel() 或 setPixel32() 方法。若要设置像素的颜色, 只需将 x、 y 坐标和颜色值传递给这两种方法之一即可。 以下示例使用 setPixel() 在绿色 BitmapData 背景上绘制交叉形状。然后,此示例使用 getPixel() 从坐标 50, 50 处的像素中检索 颜色值并跟踪返回的值。 import flash.display.Bitmap; import flash.display.BitmapData; var myBitmapData:BitmapData = new BitmapData(100, 100, false, 0x009900); for (var i:uint = 0; i < 100; i++) { var red:uint = 0xFF0000; myBitmapData.setPixel(50, i, red); myBitmapData.setPixel(i, 50, red); } var myBitmapImage:Bitmap = new Bitmap(myBitmapData); addChild(myBitmapImage); var pixelValue:uint = myBitmapData.getPixel(50, 50); trace(pixelValue.toString(16)); 如果要读取一组像素而不是单个像素的值,请使用 getPixels() 方法。此方法从作为参数传递的矩形像素数据区域中生成字节数 组。字节数组的每个元素 (即像素值)都是无符号的整数 (32 位未经相乘的像素值)。 相反,若要更改 (或设置)一组像素的值,请使用 setPixels() 方法。此方法需要联合使用两个参数 (rect 和 inputByteArray) 来输出像素数据 (inputByteArray) 的矩形区域 (rect)。 从 inputByteArray 中读取 (或写入)数据时,会为数组中的每个像素调用 ByteArray.readUnsignedInt() 方法。如果由于某些原 因, inputByteArray 未包含像素数据的整个矩形,则该方法会停止处理该点处的图像数据。 必须记住的是,对于获取和设置像素数据,字节数组需要有 32 位 Alpha、红、绿、蓝 (ARGB) 像素值。 以下示例使用 getPixels() 和 setPixels() 方法将一组像素从一个 BitmapData 对象复制到另一个对象:207ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 import flash.display.Bitmap; import flash.display.BitmapData; import flash.utils.ByteArray; import flash.geom.Rectangle; var bitmapDataObject1:BitmapData = new BitmapData(100, 100, false, 0x006666FF); var bitmapDataObject2:BitmapData = new BitmapData(100, 100, false, 0x00FF0000); var rect:Rectangle = new Rectangle(0, 0, 100, 100); var bytes:ByteArray = bitmapDataObject1.getPixels(rect); bytes.position = 0; bitmapDataObject2.setPixels(rect, bytes); var bitmapImage1:Bitmap = new Bitmap(bitmapDataObject1); addChild(bitmapImage1); var bitmapImage2:Bitmap = new Bitmap(bitmapDataObject2); addChild(bitmapImage2); bitmapImage2.x = 110; 像素级别冲突检测 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 BitmapData.hitTest() 方法可以在位图数据和另一个对象或点之间执行像素级别冲突检测。 BitmapData.hitTest() 方法接受五个参数: • firstPoint (Point):此参数指在其上执行点击测试的第一个 BitmapData 的左上角的像素位置。 • firstAlphaThreshold (uint):此参数指定对于此点击测试视为不透明的最高 Alpha 通道值。 • secondObject (Object):此参数表示影响区域。secondObject 对象可以是 Rectangle、Point、Bitmap 或 BitmapData 对 象。此对象表示在其上执行冲突检测的点击区域。 • secondBitmapDataPoint (Point):此可选参数用于在第二个 BitmapData 对象中定义像素位置。只有当 secondObject 的值 为 BitmapData 对象时,才使用此参数。默认值为 null。 • secondAlphaThreshold (uint):此可选参数表示在第二个 BitmapData 对象中视为不透明的最高 Alpha 通道值。默认值为 1。仅当 secondObject 的值是 BitmapData 对象并且这两个 BitmapData 对象都透明时,才使用此参数。 在不透明图像上执行冲突检测时,请牢记, ActionScript 会将图像视为完全不透明的矩形 (或边框)。或者,在透明的图像上 执行像素级别点击测试时,需要两个图像都是透明的。除此之外, ActionScript 还使用 Alpha 阈值参数来确定像素在哪点开 始从透明变为不透明。 以下示例创建三个位图图像并使用两个不同冲突点 (一个返回 false,另一个返回 true)检查像素冲突:208ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 import flash.display.Bitmap; import flash.display.BitmapData; import flash.geom.Point; var bmd1:BitmapData = new BitmapData(100, 100, false, 0x000000FF); var bmd2:BitmapData = new BitmapData(20, 20, false, 0x00FF3300); var bm1:Bitmap = new Bitmap(bmd1); this.addChild(bm1); // Create a red square. var redSquare1:Bitmap = new Bitmap(bmd2); this.addChild(redSquare1); redSquare1.x = 0; // Create a second red square. var redSquare2:Bitmap = new Bitmap(bmd2); this.addChild(redSquare2); redSquare2.x = 150; redSquare2.y = 150; // Define the point at the top-left corner of the bitmap. var pt1:Point = new Point(0, 0); // Define the point at the center of redSquare1. var pt2:Point = new Point(20, 20); // Define the point at the center of redSquare2. var pt3:Point = new Point(160, 160); trace(bmd1.hitTest(pt1, 0xFF, pt2)); // true trace(bmd1.hitTest(pt1, 0xFF, pt3)); // false 复制位图数据 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 要从一个图像向另一个图像复制位图数据,您可以使用以下几种方法:clone()、 copyPixels()、 copyChannel()、 draw() 和 drawWithQuality() (drawWithQuality 方法可在 Flash Player 11.3 和更高版本中使用;也可在 AIR 3.3 和更高版本中使用)。 正如名称的含义一样,clone() 方法允许您将位图数据从一个 BitmapData 对象克隆或采样到另一个对象。调用此方法时,此方 法返回一个新的 BitmapData 对象,它是与被复制的原始实例完全一样的克隆。 以下示例克隆橙色 (父级)正方形的一个副本,并将克隆放在原始父级正方形的旁边: import flash.display.Bitmap; import flash.display.BitmapData; var myParentSquareBitmap:BitmapData = new BitmapData(100, 100, false, 0x00ff3300); var myClonedChild:BitmapData = myParentSquareBitmap.clone(); var myParentSquareContainer:Bitmap = new Bitmap(myParentSquareBitmap); this.addChild(myParentSquareContainer); var myClonedChildContainer:Bitmap = new Bitmap(myClonedChild); this.addChild(myClonedChildContainer); myClonedChildContainer.x = 110; copyPixels() 方法是一种将像素从一个 BitmapData 对象复制到另一个 BitmapData 对象的快速且简便的方法。该方法会拍摄 源图像的矩形快照 (由 sourceRect 参数定义),并将其复制到另一个矩形区域(大小相等)。新 “ 粘贴 ” 的矩形的位置在 destPoint 参数中定义。209ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 copyChannel() 方法从源 BitmapData 对象中采集预定义的颜色通道值 (Alpha、红、绿或蓝),并将此值复制到目标 BitmapData 对象的通道中。调用此方法不会影响目标 BitmapData 对象中的其他通道。 draw() 和 drawWithQuality() 方法将源子画面、影片剪辑或其他显示对象中的图形内容绘制或呈现在新位图上。使用 matrix、 colorTransform、blendMode 和目标 clipRect 参数,可以修改新位图的呈示方式。此方法使用 Flash Player 和 AIR 中的矢量渲 染器生成数据。 调用 draw() 或 drawWithQuality() 时,需要将源对象 (子画面、影片剪辑或其他显示对象)作为第一个参数传递,如下所示: myBitmap.draw(movieClip); 如果源对象在最初加载后应用了变形 (颜色、矩阵等等),则不能将这些变形复制到新对象。如果想要将变形复制到新位图, 则需要将 transform 属性的值从原始对象复制到使用新 BitmapData 对象的 Bitmap 对象的 transform 属性中。 压缩位图数据 Flash Player 11.3 和更高版本, AIR 3.3 和更高版本 flash.display.BitmapData.encode() 方法允许您将位图数据本机压缩为以下图像压缩格式之一: • PNG - 使用 PNG 压缩,可以选择使用快速压缩,它强调的是压缩速度而不是文件大小。若要使用 PNG 压缩,请将新的 flash.display.PNGEncoderOptions 对象作为 BitmapData.encode() 方法的第二个参数传递。 • JPEG - 使用 JPEG 压缩,可以选择指定图像品质。若要使用 JPEG 压缩,请将新的 flash.display.JPEGEncoderOptions 对象 作为 BitmapData.encode() 方法的第二个参数传递。 • JPEGXR - 使用 JPEG 扩展范围 (XR) 压缩,可以选择指定颜色通道、损耗和熵 (entropy) 编码设置。若要使用 JPEGXR 压缩,请将新的 flash.display.JPEGXREncoderOptions 对象作为 BitmapData.encode() 方法的第二个参数传递。 您可以将图像处理的此功能用作服务器上传或下载工作流程的一部分。 下面的示例代码片段使用 JPEGEncoderOptions 压缩 BitmapData 对象: // Compress a BitmapData object as a JPEG file. var bitmapData:BitmapData = new BitmapData(640,480,false,0x00FF00); var byteArray:ByteArray = new ByteArray(); bitmapData.encode(new Rectangle(0,0,640,480), new flash.display.JPEGEncoderOptions(), byteArray); 使用杂点功能制作纹理 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 若要修改位图的外观,可以使用 noise() 方法或 perlinNoise() 方法对位图应用杂点效果。可以把杂点效果比作未调谐的电视屏幕 的静态外观。 若要对位图应用杂点效果,请使用 noise() 方法。此方法对位图图像的指定区域中的像素应用随机颜色值。 此方法接受五个参数: • randomSeed (int):决定图案的随机种子数。不管名称具有什么样的含义,只要传递的数字相同,此数字就会生成相同的结 果。为了获得真正的随机结果,请使用 Math.random() 方法为此参数传递随机数字。 • low (uint):此参数指要为每个像素生成的最低值 (0 至 255)。默认值为 0。将此参数设置为较低值会产生较暗的杂点图 案,而将此参数设置为较高值会产生较亮的图案。210ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 • high (uint):此参数指要为每个像素生成的最高值 (0 至 255)。默认值为 255。将此参数设置为较低值会产生较暗的杂点 图案,而将此参数设置为较高值会产生较亮的图案。 • channelOptions (uint):此参数指定将向位图对象的哪个颜色通道应用杂点图案。此数字可以是四个颜色通道 ARGB 值的 任意组合。默认值为 7。 • grayScale (Boolean):设置为 true 时,此参数对位图像素应用 randomSeed 值,可有效地褪去图像中的所有颜色。此参数不 影响 Alpha 通道。默认值为 false。 以下示例创建一个位图图像,并对它应用蓝色杂点图案: package { import flash.display.Sprite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; public class BitmapNoise1 extends Sprite { public function BitmapNoise1() { var myBitmap:BitmapData = new BitmapData(250, 250,false, 0xff000000); myBitmap.noise(500, 0, 255, BitmapDataChannel.BLUE,false); var image:Bitmap = new Bitmap(myBitmap); addChild(image); } } } 如果要创建更好的有机外观纹理,请使用 perlinNoise() 方法。 perlinNoise() 方法可生成逼真、有机的纹理,是用于烟雾、云 彩、水、火或爆炸的理想图案。 由于 perlinNoise() 方法是由算法生成的,因此它使用的内存比基于位图的纹理少。但还是会对处理器的使用有影响,特别是对 于旧计算机,会降低内容的处理速度,使屏幕重绘的速度比帧速率慢。这主要是因为需要进行浮点计算,以便处理 Perlin 杂点 算法。 此方法接受九个参数 (前六个是必需参数): • baseX (Number):决定创建的图案的 x (大小)值。 • baseY (Number):决定创建的图案的 y (大小)值。 • numOctaves (uint):要组合以创建此杂点的 octave 函数或各个杂点函数的数目。 octave 数目越大,创建的图像越精细, 但这需要更多的处理时间。 • randomSeed (int):随机种子数的功能与在 noise() 函数中的功能完全相同。为了获得真正的随机结果,请使用 Math.random() 方法为此参数传递随机数字。 • stitch (Boolean):如果设置为 true,则此方法尝试缝合 (或平滑)图像的过渡边缘以形成无缝的纹理,用于作为位图填充 进行平铺。 • fractalNoise (Boolean):此参数与此方法生成的渐变的边缘有关。如果设置为 true,则此方法生成的碎片杂点会对效果的边 缘进行平滑处理。如果设置为 false,则将生成湍流。带有湍流的图像具有可见的不连续性渐变,可以使用它处理更接近锐 化的视觉效果,例如,火焰或海浪。 • channelOptions (uint):channelOptions 参数的功能与在 noise() 方法中的功能完全相同。它指定对哪个颜色通道 (在位图 上)应用杂点图案。此数字可以是四个颜色通道 ARGB 值的任意组合。默认值为 7。 • grayScale (Boolean):grayScale 参数的功能与在 noise() 方法中的功能完全相同。如果设置为 true,则对位图像素应用 randomSeed 值,可有效地褪去图像中的所有颜色。默认值为 false。211ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 • offsets (Array):对应于每个 octave 的 x 和 y 偏移的点数组。通过处理偏移值,可以平滑滚动图像层。偏移数组中的每个点 将影响一个特定的 octave 杂点函数。默认值为 null。 以下示例创建一个 150 x 150 像素的 BitmapData 对象,该对象调用 perlinNoise() 方法来生成绿色和蓝色的云彩效果: package { import flash.display.Sprite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; public class BitmapNoise2 extends Sprite { public function BitmapNoise2() { var myBitmapDataObject:BitmapData = new BitmapData(150, 150, false, 0x00FF0000); var seed:Number = Math.floor(Math.random() * 100); var channels:uint = BitmapDataChannel.GREEN | BitmapDataChannel.BLUE myBitmapDataObject.perlinNoise(100, 80, 6, seed, false, true, channels, false, null); var myBitmap:Bitmap = new Bitmap(myBitmapDataObject); addChild(myBitmap); } } } 滚动位图 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 设想您创建了一个街道图应用程序,每次用户移动该图时,都需要您更新视图 (即使该图只移动了几个像素)。 创建此功能的一种方式是,每次用户移动街道图时,均重新呈示包含更新的街道图视图的新图像。或者,创建一个大型图像, 并使用 scroll() 方法。 scroll() 方法可以复制屏幕上的位图,然后将它粘贴到由 (x, y) 参数指定的新偏移位置。如果位图的一部分恰巧在舞台以外,则 会产生图像发生移位的效果。与计时器函数 (或 enterFrame 事件)配合使用时,可以使图像呈示动画或滚动效果。 以下示例采用前面的 Perlin 杂点示例并生成较大的位图图像 (其四分之三呈示在舞台外面)。然后应用 scroll() 方法和一个 enterFrame 事件侦听器,使图像在对角线向下方向偏移一个像素。每次进入帧时均会调用此方法,因此,随着图像向下滚动, 图像位于屏幕以外的部分会呈现在舞台上。212ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 import flash.display.Bitmap; import flash.display.BitmapData; var myBitmapDataObject:BitmapData = new BitmapData(1000, 1000, false, 0x00FF0000); var seed:Number = Math.floor(Math.random() * 100); var channels:uint = BitmapDataChannel.GREEN | BitmapDataChannel.BLUE; myBitmapDataObject.perlinNoise(100, 80, 6, seed, false, true, channels, false, null); var myBitmap:Bitmap = new Bitmap(myBitmapDataObject); myBitmap.x = -750; myBitmap.y = -750; addChild(myBitmap); addEventListener(Event.ENTER_FRAME, scrollBitmap); function scrollBitmap(event:Event):void { myBitmapDataObject.scroll(1, 1); } 利用 mipmap 处理 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 “MIP map” (也称为 “mipmap”)是组合在一起并与纹理关联的位图,可改善运行时呈示品质和性能。 MIP map 中的每个 位图图像分别是主位图图像的一个版本,但与主图像相比,其详细程度有所降低。 例如,您的 MIP map 可以包括 64 × 64 像素的最高品质的主图像。 MIP map 中的较低品质图像将为 32 × 32、 16 × 16、 8 × 8、 4 × 4、 2 × 2 和 1 × 1 像素。 “ 纹理流式处理 ” 是首先加载最低品质的位图,然后在加载位图时逐渐显示较高品质的位图的功能。因为较低品质的位图较小, 所以它们的加载速度比主图像快。因此,应用程序用户可以在高品质的主位图加载之前,在应用程序中查看图像。 Flash Player 9.115.0 和更高版本及 AIR 通过创建每个位图的不同显示比例 (从 50% 开始)的优化版本来实现此技术 (该过 程称为 “mipmap 处理 ”)。 Flash Player 11.3 和 AIR 3.3 支持通过 Context3D.createCubeTexture() 和 Context3D.createTexture() 方法的 streamingLevels 参数执行纹理流式处理。 使用纹理压缩可以将纹理图像以压缩格式直接存储在 GPU 中,从而节省 GPU 内存和内存带宽。通常,纹理的压缩是脱机进 行的,且压缩后的纹理以压缩格式上传到 GPU。不过, Flash Player 11.4 和 AIR 3.4 支持运行时纹理压缩,这在某些情况下 非常有用,比如渲染矢量图中的动态纹理时。 要使用运行时纹理压缩,可执行以下步骤: • 通过调用 Context3D.createTexture() 方法创建纹理对象,在第三个参数中传递 flash.display3D.Context3DTextureFormat.COMPRESSED 或 flash.display3D.Context3DTextureFormat.COMPRESSED_ALPHA。 • 使用 createTexture() 返回的 flash.display3D.textures.Texture 实例,调用 flash.display3D.textures.Texture.uploadFromBitmapData() 或 flash.display3D.textures.Texture.uploadFromByteArray()。这些 方法会在单独一个步骤中执行纹理的上传和压缩。 为以下位图类型创建 MIP 映射: • 使用 ActionScript 3.0 Loader 类显示的位图 (JPEG、 GIF 或 PNG 文件) • Flash Professional 文档库中的位图 • BitmapData 对象213ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 • 使用 ActionScript 2.0 loadMovie() 函数显示的位图 MIP map 不适用于应用滤镜的对象或缓存位图的影片剪辑。不过,如果应用滤镜的显示对象中包含位图转换,则即使位图位 于被遮罩的内容中,也会应用 MIP map。 Mipmap 处理是自动执行的,但您可以遵循几条准则,以确保您的图像利用此优化技术: • 对于视频播放,请将 Video 对象的 smoothing 属性设置为 true (请参阅 Video 类)。 • 对于位图,不一定要将 smoothing 属性设置为 true,但当位图使用平滑处理时品质的改善更为显著。 • 对于二维图像,请使用可被 4 或 8 整除的位图大小 (如 640 x 128,可按如下方式递减:320 x 64 > 160 x 32 > 80 x 16 > 40 x 8 > 20 x 4 > 10 x 2 > 5 x 1)。 对于三维纹理,使用其中每个图像的分辨率为 2 的幂 (即 2^n)的 MIP map。例如,主图像的分辨率为 1024 x 1024 像 素。这样,MIP map 中较低品质的图像将为 512 x 512、256 x 256、128 x 128,直至 1 x 1 像素,分别针对 MIP map 中 的总共 11 个图像。 请注意,不会对宽度或高度为奇数的位图内容执行 Mipmap 处理。 位图示例:带动画效果的旋转的月亮 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 旋转的月球动画示例说明了位图对象和位图图像数据 (BitmapData 对象)的使用方法。该示例使用月球表面的平面图像作为 原始图像数据来创建一个旋转的月球动画。将对以下方法进行说明: • 加载外部图像并访问其原始图像数据 • 通过重复复制源图像不同部分的像素创建动画 • 通过设置像素值创建位图图像 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在 Samples/SpinningMoon 文件夹中找到 “ 旋转的月球动画 ” 的应用程序文件。该应用程序包含以下文件: 将外部图像作为位图数据加载 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 此范例执行的第一项主要任务是加载外部图像文件,即月球表面照片。加载操作由 MoonSphere 类中的两个方法处理: MoonSphere() 构造函数 (启动加载过程)和 imageLoadComplete() 方法 (完成外部图像加载后调用该方法)。 加载外部图像与加载外部 SWF 类似,两者都使用 flash.display.Loader 类的实例执行加载操作。启动图像加载的 MoonSphere() 方法中的实际代码如下: 文件 说明 SpinningMoon.mxml 或 SpinningMoon.fla Flex (MXML) 或 Flash (FLA) 中的主应用程序文件。 com/example/programmingas3/moon/MoonSphere.as 用于执行加载、显示月球和创建月球动画的功能的类。 moonMap.png 包含月球表面照片的图像文件 (将加载此图像文件并使用它来创建旋转的月 球动画)。214ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 var imageLoader:Loader = new Loader(); imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoadComplete); imageLoader.load(new URLRequest("moonMap.png")); 第一行声明名为 imageLoader 的 Loader 实例。第三行通过调用 Loader 对象的 load() 方法并传递一个 URLRequest 实例(表 示要加载的图像的 URL)来实际启动加载过程。第二行设置在完成图像加载时将触发的事件侦听器。请注意:不是对 Loader 实例本身调用 addEventListener() 方法;而是对 Loader 对象的 contentLoaderInfo 属性调用该方法。Loader 实例本身不会调度 与所加载内容相关的事件。然而,它的 contentLoaderInfo 属性包含对 LoaderInfo 对象的引用,该对象与加载到 Loader 对象 的内容 (本例中为外部图像)相关联。该 LoaderInfo 对象提供与外部内容加载进度及加载完成有关的几个事件,其中包括 complete 事件 (Event.COMPLETE),该事件将在完成图像加载时触发对 imageLoadComplete() 方法的调用。 启动外部图像加载是加载过程中的重要部分,而了解加载完成时要执行什么操作也同等重要。如以上代码所示,完成加载图像 后将调用 imageLoadComplete() 函数。该函数对加载的图像数据执行一些操作,稍后将进行说明。然而,若要使用图像数据, 还需要访问该数据。当使用某 Loader 对象来加载外部图像时,加载的图像将变为一个 Bitmap 实例,并附加为该 Loader 对象 的一个子显示对象。在本例中, Loader 实例可作为事件对象的一部分用于事件侦听器方法,此事件对象将作为参数传递给该 方法。 imageLoadComplete() 方法的前几行如下: private function imageLoadComplete(event:Event):void { textureMap = event.target.content.bitmapData; ... } 请注意,事件对象参数名为 event,它是 Event 类的一个实例。Event 类的每个实例都具有一个 target 属性,该属性将引用触发 事件的对象 (本例中为 LoaderInfo 实例,如前所述,将对该实例调用 addEventListener() 方法。)而 LoaderInfo 对象又具有 一个 content 属性,加载过程完成后,该属性将包含 Bitmap 实例,其中具有加载的位图图像。如果要在屏幕上直接显示该图 像,则可以将此 Bitmap 实例 (event.target.content) 附加到一个显示对象容器。(也可以将 Loader 对象附加到一个显示对象容 器。)但是,在该示例中,加载的内容将用作原始图像数据的源而不是显示在屏幕上。因此,imageLoadComplete() 方法的第一 行读取加载的 Bitmap 实例的 bitmapData 属性 (event.target.content.bitmapData),并将其存储在名为 textureMap 的实例变量 中,该变量用作创建旋转的月球动画的图像数据源。将稍后对此进行说明。 通过复制像素创建动画 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 动画的基本定义是通过随时间变化改变图像而产生的运动或变化的视觉效果。此示例的目标是创建月球绕其垂直轴旋转的视觉 效果。然而,对于动画而言,您可以忽略该示例中球形扭曲方面的问题。假设已加载并用作月球图像数据源的实际图像如下: 如您所见,该图像并不是一个或几个球体;它是月球表面的一张矩形照片。因为该照片刚好是在月球赤道上拍摄的,所以图像 中靠近图像顶部和底部的部分发生拉伸和扭曲。若要消除图像的扭曲使其具有球形外观,我们将使用置换图滤镜 (在后面进行 介绍)。但是,因为该源图像是矩形,所以若要产生旋转球体的视觉效果,代码只要能完成水平滑动月球表面照片的操作即可。 请注意,该图像实际上由月球表面照片的两个副本彼此相接而成。该图像是要从中重复复制图像数据来创建动画外观的源图 像。通过两个图像副本彼此相接,会更容易产生连续、不间断的滚动效果。让我们逐步浏览动画生成的过程来看看这是如何实 现的。215ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 该过程实际上涉及两个单独的 ActionScript 对象。首先,有加载的源图像,在代码中由名为 textureMap 的 BitmapData 实例 表示。如前所述,外部图像加载后,将用图像数据来填充 textureMap,使用的代码如下: textureMap = event.target.content.bitmapData; textureMap 的内容是矩形的月球图像。另外,为了产生旋转动画,该代码使用名为 sphere 的 Bitmap 实例,该实例是在屏幕上 显示月球图像的实际显示对象。与 textureMap 一样,sphere 对象也是在 imageLoadComplete() 方法中创建并使用其初始图像数 据填充,使用的代码如下: sphere = new Bitmap(); sphere.bitmapData = new BitmapData(textureMap.width / 2, textureMap.height); sphere.bitmapData.copyPixels(textureMap, new Rectangle(0, 0, sphere.width, sphere.height), new Point(0, 0)); 如代码所示,sphere 被实例化了。其 bitmapData 属性 (通过 sphere 显示的原始图像数据)具有与 textureMap 相同的高度和一 半的宽度。换句话说,sphere 的内容将是一幅月球照片的大小 (因为 textureMap 图像包含并排的两幅月球照片)。接下来,用 图像数据填充 bitmapData 属性,填充时使用的是 copyPixels() 方法。 copyPixels() 方法调用中的参数指示以下几点: • 第一个参数指示从 textureMap 复制图像数据。 • 第二个参数 (新的 Rectangle 实例)指定图像快照应该从 textureMap 的哪部分拍摄;在本例中,快照是从 textureMap 左 上角开始的一个矩形(由前两个 Rectangle() 参数 0, 0 指示),矩形快照的宽度和高度与 sphere 的 width 和 height 属性一致。 • 第三个参数 (新的 Point 实例)的 x 和 y 值都为 0,它定义了像素数据的目标位置 — 本例中为 sphere.bitmapData 的左上 角 (0, 0)。 从视觉表示形式上看,该代码将复制下图中用轮廓线标出的、textureMap 的像素,并将其粘贴到 sphere 上。换句话说,sphere 的 BitmapData 内容是这里加亮的 textureMap 部分: 然而请记住,这只是 sphere 的初始状态 — 复制到 sphere 上的第一项图像内容。 加载源图像并创建 sphere 之后,由 imageLoadComplete() 方法执行的最终任务是设置动画。动画由名为 rotationTimer 的 Timer 实例驱动,该实例由以下代码创建并启动: var rotationTimer:Timer = new Timer(15); rotationTimer.addEventListener(TimerEvent.TIMER, rotateMoon); rotationTimer.start(); 代码首先创建名为 rotationTimer 的 Timer 实例;传递给 Timer() 构造函数的参数指示 rotationTimer 应每 15 毫秒触发一次其 timer 事件。接下来将调用 addEventListener() 方法,以指定在发生 timer 事件 (TimerEvent.TIMER) 时调用 rotateMoon() 方法。 最后,计时器实际上是通过调用其 start() 方法启动的。 根据 rotationTimer 的定义方式,约每 15 毫秒 Flash Player 调用一次 MoonSphere 类中的 rotateMoon() 方法 (用于产生月 球动画)。 rotateMoon() 方法的源代码如下:216ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 private function rotateMoon(event:TimerEvent):void { sourceX += 1; if (sourceX > textureMap.width / 2) { sourceX = 0; } sphere.Data.copyPixels(textureMap, new Rectangle(sourceX, 0, sphere.width, sphere.height), new Point(0, 0)); event.updateAfterEvent(); } 该代码实现以下三方面的操作: 1 变量 sourceX 的值 (最初设为 0)增加 1。 sourceX += 1; 您将看到, sourceX 用于确定 textureMap 中的位置 (从该位置将像素复制到 sphere),因此该代码会产生在 textureMap 上 将矩形向右移动一个像素的效果。返回到视觉表示形式,经过几个动画循环之后,源矩形将向右移动几个像素,如下所示: 经过几个循环之后,矩形将进一步移动: 像素复制位置的这种平稳渐进式移动是动画制作的关键。通过缓慢、连续地将源位置移动到右侧,sphere 中显示在屏幕上的 图像显示为连续地滑向左侧。这就是源图像 (textureMap) 需要两个月球表面照片副本的原因。由于矩形连续移动到右侧, 因此大多数时间该矩形不是在一张月球照片上而是与两张月球照片发生重叠。217ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 2 随着源矩形缓慢移到右侧,会出现一个问题。最后,矩形将到达 textureMap 的右边缘,它将用完要复制到 sphere 上的月球 照片像素: 下一行代码将解决这个问题: if (sourceX >= textureMap.width / 2) { sourceX = 0; } 该代码检查 sourceX (矩形的左边缘)是否已到达 textureMap 的中部。如果是,它会将 sourceX 重置为 0,将其移回到 textureMap 的左边缘并重新开始循环: 3 计算出适当的 sourceX 值后,创建动画的最后一步是将新的源矩形像素实际复制到 sphere 上。实现这一操作的代码与最初 填充 sphere 的代码 (如前面所述)非常类似;唯一的不同是:在本例的 new Rectangle() 构造函数调用中,矩形的左边缘位 于 sourceX: sphere.bitmapData.copyPixels(textureMap, new Rectangle(sourceX, 0, sphere.width, sphere.height), new Point(0, 0)); 请记住,此代码每 15 毫秒重复调用一次。由于源矩形的位置是连续移动的,并且像素被复制到 sphere 上,因此在屏幕上显示 为由 sphere 表示的月球照片图像发生连续滑动。换句话说,月球显示为连续旋转。 创建球形外观 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当然,月球是一个球体而不是一个矩形。由于要形成连续动画,因此该示例需要拍摄矩形的月球表面照片,并将其转换成球 体。这涉及两个单独的步骤:一个用于隐藏月球表面照片中除圆形区域之外的所有内容的遮罩,以及一个用于扭曲月球照片外 观使其具有三维外观的置换图滤镜。 首先,圆形遮罩用于隐藏 MoonSphere 对象中除通过滤镜创建的球体之外的所有内容。以下代码创建一个作为 Shape 实例的 遮罩,并将其应用为 MoonSphere 实例的遮罩:218ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 moonMask = new Shape(); moonMask.graphics.beginFill(0); moonMask.graphics.drawCircle(0, 0, radius); this.addChild(moonMask); this.mask = moonMask; 请注意,由于 MoonSphere 是一个显示对象 (它基于 Sprite 类),因此可以使用该显示对象继承的 mask 属性将遮罩直接应 用于 MoonSphere 实例。 仅使用圆形遮罩隐藏照片的某些部分不足以创建逼真的旋转球体效果。由于月球表面照片拍摄方式的限制,导致照片的尺寸不 成比例;与赤道上的部分相比,图像上越靠近图像顶部或底部的部分扭曲和拉伸得越严重。为了对月球照片的外观进行变形以 使其具有三维效果,我们将使用置换图滤镜。 置换图滤镜是一种用于扭曲图像的滤镜。在本例中,将通过水平挤压图像的顶部和底部而保持中部不变来 “ 扭曲 ” 月球照片, 从而使其看起来更加逼真。假设对照片的正方形部分执行滤镜操作,挤压顶部和底部而不挤压中部将使正方形变为圆形。为该 扭曲图像添加动画效果所产生的另一效果是:与靠近顶部和底部的区域相比,图像的中部看起来所移动的实际像素距离更大, 这将产生圆实际上是一个三维对象 (球体)的视觉效果。 以下代码用于创建名为 displaceFilter 的置换图滤镜: var displaceFilter:DisplacementMapFilter; displaceFilter = new DisplacementMapFilter(fisheyeLens, new Point(radius, 0), BitmapDataChannel.RED, BitmapDataChannel.GREEN, radius, 0); 第一个参数 fisheyeLens 称为置换图图像;在本例中,它是以编程方式创建的 BitmapData 对象。将在第 219 页的 “ 通过设置 像素值创建位图图像 ” 中介绍创建该图像的说明。其他参数说明过滤后的图像中应该应用滤镜的位置、使用哪些颜色通道来控 制置换效果以及将在何种范围内对置换产生影响。一旦创建置换图滤镜,它将应用于仍位于 imageLoadComplete() 方法中的 sphere: sphere.filters = [displaceFilter]; 应用了遮罩和置换图滤镜的最终图像如下所示:219ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 每个旋转月球动画循环之后, sphere 的 BitmapData 内容将由新的源图像数据快照覆盖。但是,无需每次都重新应用滤镜。 这是因为滤镜应用到了 Bitmap 实例 (显示对象)而不是位图数据 (原始像素信息)。请记住, Bitmap 实例不是实际的位图 数据;它是在屏幕上显示位图数据的显示对象。举例来说, Bitmap 实例就像用于在屏幕上显示照片幻灯片的幻灯片放映机, 而 BitmapData 对象就像可以通过幻灯片放映机显示的实际照片幻灯片。滤镜可以直接应用于 BitmapData 对象,这与直接在 照片幻灯片上绘图以更改图像相似。滤镜也可以应用于任何显示对象 (包括 Bitmap 实例);这与在幻灯片放映机的镜头前面 放一个滤镜以使屏幕上显示的输出变形 (丝毫不会更改原始幻灯片)相似。因为可通过 Bitmap 实例的 bitmapData 属性来访 问原始位图数据,所以滤镜可能已直接应用于原始位图数据。然而,在本例中,将滤镜应用于 Bitmap 显示对象比应用于位图 数据更有意义。 有关在 ActionScript 中使用置换图滤镜的详细信息,请参阅第 224 页的 “ 过滤显示对象 ”。 通过设置像素值创建位图图像 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 置换图滤镜的一个重要方面是它实际上涉及两个图像。一个图像为源图像,即由滤镜实际更改的图像。在该示例中,源图像是 名为 sphere 的 Bitmap 实例。滤镜所用的另一个图像称为映射图像。映射图像不实际显示在屏幕上。相反,它的每个像素的颜 色都用作置换函数的输入 — 置换图图像中位于特定 x、y 坐标的像素的颜色决定应用于源图像中位于该 x、y 坐标的像素的置换 量 (物理位移)。 因此,为了使用置换图滤镜创建球体效果,该范例需要合适的置换图图像 — 一个包含灰色背景和用单一颜色 (红色)从暗到 亮水平渐变填充的圆的图像,如下图所示: 因为该示例中仅使用一个映射图像和滤镜,所以在 imageLoadComplete() 方法中 (换句话说,外部图像完成加载时)只创建一 次映射图像。通过调用 MoonSphere 类的 createFisheyeMap() 方法来创建名为 fisheyeLens 的置换图图像: var fisheyeLens:BitmapData = createFisheyeMap(radius); 在 createFisheyeMap() 方法中,在使用 BitmapData 类的 setPixel() 方法绘制置换图图像时,实际上每次只绘制一个像素。下面 列出了 createFisheyeMap() 方法的完整代码,并跟有操作方式的逐步说明:220ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 private function createFisheyeMap(radius:int):BitmapData { var diameter:int = 2 * radius; var result:BitmapData = new BitmapData(diameter, diameter, false, 0x808080); // Loop through the pixels in the image one by one for (var i:int = 0; i < diameter; i++) { for (var j:int = 0; j < diameter; j++) { // Calculate the x and y distances of this pixel from // the center of the circle (as a percentage of the radius). var pctX:Number = (i - radius) / radius; var pctY:Number = (j - radius) / radius; // Calculate the linear distance of this pixel from // the center of the circle (as a percentage of the radius). var pctDistance:Number = Math.sqrt(pctX * pctX + pctY * pctY); // If the current pixel is inside the circle, // set its color. if (pctDistance < 1) { // Calculate the appropriate color depending on the // distance of this pixel from the center of the circle. var red:int; var green:int; var blue:int; var rgb:uint; red = 128 * (1 + 0.75 * pctX * pctX * pctX / (1 - pctY * pctY)); green = 0; blue = 0; rgb = (red << 16 | green << 8 | blue); // Set the pixel to the calculated color. result.setPixel(i, j, rgb); } } } return result; } 首先,调用该方法时,将接收参数 radius,指示要创建的圆形图像的半径。接下来,该代码将创建 BitmapData 对象 (将在该 对象上绘制圆)。该对象名为 result,最终将作为该方法的返回值传递回来。如以下代码片断所示, result BitmapData 实例将 使用与圆直径相同的宽度和高度创建,且不透明 (第三个参数为 false),用颜色 0x808080 (中灰色)预先填充: var result:BitmapData = new BitmapData(diameter, diameter, false, 0x808080); 接下来,该代码使用两个循环遍历图像的每个像素。外部循环从左到右遍历图像的每一列 (使用变量 i 表示当前所操作的像素 的水平位置),而内部循环从上到下遍历当前列的每个像素(使用变量 j 表示当前像素的垂直位置)。下面显示了循环的代码 (省略了内部循环的内容):221ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 for (var i:int = 0; i < diameter; i++) { for (var j:int = 0; j < diameter; j++) { ... } } 由于循环逐个遍历像素,因此会为每个像素计算一个值 (映射图像中该像素的颜色值)。此过程包含四个步骤: 1 代码计算当前像素沿 x 轴距离圆心的距离 (i - radius)。该值除以半径得到半径的百分比而不是绝对距离 ((i - radius) / radius)。该百分比值存储在名为 pctX 的变量中,而且会计算沿 y 轴的等效值并存储在变量 pctY,如以下代码所示: var pctX:Number = (i - radius) / radius; var pctY:Number = (j - radius) / radius; 2 使用标准三角公式 (勾股定理),通过 pctX 和 pctY 计算圆心和当前点之间的直线距离。该值存储在名为 pctDistance 的变 量中,如下所示: var pctDistance:Number = Math.sqrt(pctX * pctX + pctY * pctY); 3 接下来,代码将检查距离百分比是否小于 1 (也就是半径的 100%,或者换句话说,所考虑的像素是否处于圆的半径范围之 内。如果该像素落在圆内,将被指定一个计算得到的颜色值 (此处省略,在步骤 4 中介绍);如果不落在圆内,该像素将 不发生任何变化,其颜色保留为默认的中灰色: if (pctDistance < 1) { ... } 4 对于落在圆内的那些像素,将为其计算一个颜色值。最终颜色将呈现红色色调,范围从圆左边缘的黑 (0%) 红到圆右边缘的 亮 (100%) 红。颜色值最初按三部分 (红、绿和蓝)计算,如下所示: red = 128 * (1 + 0.75 * pctX * pctX * pctX / (1 - pctY * pctY)); green = 0; blue = 0; 请注意,实际上只有颜色的红色部分 (变量 red)有一个值。为清楚起见,此处显示了绿色和蓝色值 (变量 green 和 blue),不过可以省略。因为该方法的目的是创建一个包含红色渐变的圆,所以不需要绿色和蓝色。 三个颜色值都确定之后,将使用标准移位算法组合成一个整数颜色值,如以下代码所示: rgb = (red << 16 | green << 8 | blue); 最后,计算出颜色值后,使用 result BitmapData 对象的 setPixel() 方法将该颜色值实际赋给当前像素,如下所示: result.setPixel(i, j, rgb); 位图图像的异步解码 Flash Player 11 和更高版本, Adobe AIR 2.6 和更高版本 使用位图图像时,可以异步解码和加载位图图像,以改善应用程序的感知性能。在许多情况下,异步解码位图图像所需的时间 可能和同步解码图像相同。但是,在关联的 Loader 对象发送 COMPLETE 事件之前,位图图像会在单独的线程中进行解码。因 此,您可以在加载较大的图像后,对其进行异步解码。 借助 flash.system 包中的 ImageDecodingPolicy 类,您可以指定位图加载方案。默认加载方案为异步。222ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 注: 如果加载的文件是位图图像,并且使用的解码策略为 ON_LOAD,则该图像将在 COMPLETE 事件调度之前进行异步解 码。 以下代码显示了 ImageDecodingPolicy 类的用法: var loaderContext:LoaderContext = new LoaderContext(); loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_LOAD var loader:Loader = new Loader(); loader.load(new URLRequest("http://www.adobe.com/myimage.png"), loaderContext); 您仍然可以通过 Loader.load() 和 Loader.loadBytes() 方法使用 ON_DEMAND 解码。但是,所有其他使用 LoaderContext 对象作 为参数的方法,将忽略传递的任何 ImageDecodingPolicy 值。 下面的示例显示了同步和异步解码位图图像的差异: package { import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.net.URLRequest; import flash.system.ImageDecodingPolicy; import flash.system.LoaderContext; public class AsyncTest extends Sprite { private var loaderContext:LoaderContext; private var loader:Loader; private var urlRequest:URLRequest; public function AsyncTest() { //Load the image synchronously loaderContext = new LoaderContext(); //Default behavior. loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_DEMAND; loader = new Loader(); loadImageSync(); //Load the image asynchronously loaderContext = new LoaderContext(); loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_LOAD; loader = new Loader(); loadImageASync(); } private function loadImageASync():void{ trace("Loading image asynchronously..."); urlRequest = new URLRequest("http://www.adobe.com/myimage.png"); 位图解码策略 位图加载方案 说明 ImageDecodingPolicy.ON_DEMAND 同步 在访问图像数据时,对加载的图像进行解码。 使用此策略可以解码较小的图像。如果您的 应用程序不依赖复杂的效果或过渡,则也可 以使用此策略。 ImageDecodingPolicy.ON_LOAD 异步 在加载时,在调度 COMPLETE 事件之前对 加载的图像进行解码。 此策略是处理较大 (大于 10 MP)图像的理 想之选。当开发具有页面过渡效果的基于 AIR 的移动应用程序时,使用此位图加载策 略可以改善应用程序的感知性能。223ACTIONSCRIPT 3.0 开发人员指南 使用位图 上次更新 2014/12/1 urlRequest.useCache = false; loader.load(urlRequest, loaderContext); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onAsyncLoadComplete); } private function onAsyncLoadComplete(event:Event):void{ trace("Async. Image Load Complete"); } private function loadImageSync():void{ trace("Loading image synchronously..."); urlRequest = new URLRequest("http://www.adobe.com/myimage.png"); urlRequest.useCache = false; loader.load(urlRequest, loaderContext); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onSyncLoadComplete); } private function onSyncLoadComplete(event:Event):void{ trace("Sync. Image Load Complete"); } } } 有关不同解码策略的效果说明,请参阅 Thibaud Imbert:Adobe Flash 运行时中的异步位图解码224 上次更新 2014/12/1 第 14 章 : 过滤显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 以往,对位图图像应用滤镜效果是专业图像编辑软件 (如 Adobe Photoshop® 和 Adobe Fireworks®)的范畴。 ActionScript 3.0 包括 flash.filters 包,其中包含一系列位图效果滤镜类。使用这些效果,开发人员可以编程方式对位图应用 滤镜并显示对象,以达到图形处理应用程序中所具有的许多相同效果。 过滤显示对象的基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 为应用程序添加优美效果的一种方式是添加简单的图形效果。您可以在图片后面添加投影以产生三维视觉效果,或在按钮周围 添加发光效果以表示该按钮当前处于活动状态。 ActionScript 3.0 包括十种可应用于任何显示对象或 BitmapData 实例的滤 镜。内置滤镜的范围从基本滤镜 (如投影和发光滤镜)到复杂滤镜 (如置换图滤镜和卷积滤镜)。 注: 除了内置滤镜外,您还可以使用 Pixel Bender 来设计自定义滤镜和效果。 请参阅第 251 页的 “ 使用 Pixel Bender 着色器 ”。 重要概念和术语 以下参考列表包含创建滤镜时可能会遇到的重要术语: 斜面 通过在两个面变使像素变亮并在相对两个面使像素变暗创建的一个边缘。此效果可产生三维边框的外观。该效果常用于凸 起或凹进按钮和类似图形。 卷积 通过使用各种比率将每个像素的值与其周围的某些像素或全部像素的值合并,使图像中的像素发生扭曲。 置换 将图像中的像素偏移或移动到新位置。 Matrix 用于通过将网格中的数字应用到多个值然后合并这些结果来执行某些数学计算的数字网格。 更多帮助主题 flash.filters 包 flash.display.DisplayObject.filters flash.display.BitmapData.applyFilter() 创建和应用滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用滤镜可以对位图和显示对象应用从投影到斜角和模糊等各种效果。由于将每个滤镜定义为一个类,因此应用滤镜涉及创建 滤镜对象的实例,这与构造任何其他对象并没有区别。创建了滤镜对象的实例后,通过使用该对象的 filters 属性可以很容易地 将此实例应用于显示对象;如果是 BitmapData 对象,可以使用 applyFilter() 方法。225ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 创建滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 若要创建滤镜对象,只需调用所选的滤镜类的构造函数方法即可。例如,若要创建 DropShadowFilter 对象,请使用以下代 码: import flash.filters.DropShadowFilter; var myFilter:DropShadowFilter = new DropShadowFilter(); 虽然此处没有显示参数,但 DropShadowFilter() 构造函数 (与所有滤镜类的构造函数一样)接受多个可用于自定义滤镜效果外 观的可选参数。 应用滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 构造滤镜对象后,可以将其应用于显示对象或 BitmapData 对象;应用滤镜的方式取决于为之应用该滤镜的对象。 对显示对象应用滤镜 对显示对象应用滤镜效果时,可以通过 filters 属性应用这些效果。显示对象的 filters 属性是一个 Array 实例,其中的元素是应 用于该显示对象的滤镜对象。若要对显示对象应用单个滤镜,请创建该滤镜实例,将其添加到 Array 实例,再将该 Array 对象 分配给显示对象的 filters 属性: import flash.display.Bitmap; import flash.display.BitmapData; import flash.filters.DropShadowFilter; // Create a bitmapData object and render it to screen var myBitmapData:BitmapData = new BitmapData(100,100,false,0xFFFF3300); var myDisplayObject:Bitmap = new Bitmap(myBitmapData); addChild(myDisplayObject); // Create a DropShadowFilter instance. var dropShadow:DropShadowFilter = new DropShadowFilter(); // Create the filters array, adding the filter to the array by passing it as // a parameter to the Array() constructor. var filtersArray:Array = new Array(dropShadow); // Assign the filters array to the display object to apply the filter. myDisplayObject.filters = filtersArray; 如果要为该对象分配多个滤镜,只需在将 Array 实例分配给 filters 属性之前将所有滤镜添加到该实例即可。可以通过将多个对 象作为参数传递给 Array 的构造函数,将多个对象添加到 Array。例如,以下代码对上面创建的显示对象应用斜角滤镜和发光 滤镜: import flash.filters.BevelFilter; import flash.filters.GlowFilter; // Create the filters and add them to an array. var bevel:BevelFilter = new BevelFilter(); var glow:GlowFilter = new GlowFilter(); var filtersArray:Array = new Array(bevel, glow); // Assign the filters array to the display object to apply the filter. myDisplayObject.filters = filtersArray;226ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 在创建包含滤镜的数组时,您可以使用 new Array() 构造函数创建该数组 (如前面示例所示),也可以使用 Array 文本语法将 滤镜括在中括号 ([]) 中。例如,下面这行代码: var filters:Array = new Array(dropShadow, blur); 与下面这行代码效果相同: var filters:Array = [dropShadow, blur]; 如果对显示对象应用多个滤镜,则会按顺序以累积方式应用这些滤镜。例如,如果滤镜数组有两个元素:先添加的斜角滤镜和 后添加的投影滤镜,则投影滤镜既会应用于斜角滤镜,也会应用于显示对象。这是由于投影滤镜在滤镜数组中位于第二个位 置。如果想要以非累积方式应用滤镜,可对显示对象的新副本应用每个滤镜。 如果只为显示对象分配一个或几个滤镜,则可以先创建该滤镜实例,然后在单个语句中将该实例分配给该对象。例如,下面的 一行代码将模糊滤镜应用于名为 myDisplayObject 的显示对象: myDisplayObject.filters = [new BlurFilter()]; 上面的代码使用 Array 文本语法 (中括号)创建一个 Array 实例,并创建一个 BlurFilter 实例作为 Array 中的一个元素,然 后将该 Array 分配给名为 myDisplayObject 的显示对象的 filters 属性。 删除显示对象中的滤镜 删除显示对象中的所有滤镜非常简单,只需为 filters 属性分配一个 null 值即可: myDisplayObject.filters = null; 如果您已对一个对象应用了多个滤镜,并且只想删除其中一个滤镜,则必须完成多个步骤才能更改 filters 属性数组。有关详细 信息,请参阅第 226 页的 “ 使用滤镜的潜在问题 ”。 对 BitmapData 对象应用滤镜 对 BitmapData 对象应用滤镜需要使用 BitmapData 对象的 applyFilter() 方法: var rect:Rectangle = new Rectangle(); var origin:Point = new Point(); myBitmapData.applyFilter(sourceBitmapData, rect, origin, new BlurFilter()); applyFilter() 方法会对源 BitmapData 对象应用滤镜,从而生成一个新的、应用滤镜的图像。此方法不会修改原始的源图像; 而是将对源图像应用滤镜的结果存储在调用 applyFilter() 方法的 BitmapData 实例中。 滤镜的工作原理 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 显示对象过滤是通过将原始对象的副本缓存为透明位图来工作的。 将滤镜应用于显示对象后,只要此对象具有有效的滤镜列表,运行时会将该对象缓存为位图。然后,将此位图用作所有后续应 用的滤镜效果的原始图像。 每个显示对象通常包含两个位图:一个包含原始未过滤的源显示对象,另一个用于过滤后的最终图像。呈示时使用最终图像。 只要显示对象不发生更改,最终图像就不需要更新。 使用滤镜的潜在问题 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用滤镜时要记住几个导致混淆或问题的潜在根源。227ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 滤镜和位图缓存 若要对显示对象应用滤镜,必须启用该对象的位图缓存。对其 cacheAsBitmap 属性设置为 false 的显示对象应用滤镜时,该对象 的 cacheAsBitmap 属性会自动设置为 true。如果稍后删除了显示对象的所有滤镜,则 cacheAsBitmap 属性会重置为最后设置的 值。 在运行时更改滤镜 如果显示对象已应用了一个或多个滤镜,则不能通过在 filters 属性数组中添加或删除滤镜来更改滤镜组。若要添加或更改要应 用的滤镜组,必须对单独的数组进行更改,然后将该数组分配给显示对象的 filters 属性以对该对象应用滤镜。执行此操作最简 单方法是将 filters 属性数组读入 Array 变量,然后对此临时数组进行修改。然后,将此数组重新分配回显示对象的 filters 属 性。在较复杂的情况下,可能需要保留一个单独的主滤镜数组。可以对该主滤镜数组进行任何更改,并在每次更改后将该主数 组重新分配给显示对象的 filters 属性。 添加其他滤镜 下面的代码演示向已应用一个或多个滤镜的显示对象添加其他滤镜的过程。首先,对名为 myDisplayObject 的显示对象应用发 光滤镜,然后,在单击该显示对象时,调用 addFilters() 函数。在此函数中,另有两个滤镜应用于 myDisplayObject: import flash.events.MouseEvent; import flash.filters.*; myDisplayObject.filters = [new GlowFilter()]; function addFilters(event:MouseEvent):void { // Make a copy of the filters array. var filtersCopy:Array = myDisplayObject.filters; // Make desired changes to the filters (in this case, adding filters). filtersCopy.push(new BlurFilter()); filtersCopy.push(new DropShadowFilter()); // Apply the changes by reassigning the array to the filters property. myDisplayObject.filters = filtersCopy; } myDisplayObject.addEventListener(MouseEvent.CLICK, addFilters); 从一组滤镜中删除一个滤镜 如果显示对象已经应用了多个滤镜,您希望删除其中的一个滤镜并希望其他滤镜继续应用于该对象,请将这些滤镜复制到一个 临时数组中,从该数组中删除不需要的滤镜,然后将该临时数组重新分配给该显示对象的 filters 属性。第 26 页的 “ 检索值和删 除数组元素 ” 一节介绍了从任意数组删除一个或多个元素的几种方法。 最简单的情况是删除对象上最顶层的滤镜 (最后一个应用于对象的滤镜)。可以使用 Array 类的 pop() 方法从数组中删除滤 镜: // Example of removing the top-most filter from a display object // named "filteredObject". var tempFilters:Array = filteredObject.filters; // Remove the last element from the Array (the top-most filter). tempFilters.pop(); // Apply the new set of filters to the display object. filteredObject.filters = tempFilters; 同样,若要删除最底层的滤镜 (第一个应用于对象的滤镜),也可以使用相同的代码,不过需要用 Array 类的 shift() 方法替换 pop() 方法。228ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 若要从滤镜数组的中间删除滤镜 (假定该数组有两个以上的滤镜),则可以使用 splice() 方法。您必须知道要删除的滤镜的索 引 (在数组中的位置)。例如,下面的代码从显示对象中删除第二个滤镜(索引 1 处的滤镜): // Example of removing a filter from the middle of a stack of filters // applied to a display object named "filteredObject". var tempFilters:Array = filteredObject.filters; // Remove the second filter from the array. It's the item at index 1 // because Array indexes start from 0. // The first "1" indicates the index of the filter to remove; the // second "1" indicates how many elements to remove. tempFilters.splice(1, 1); // Apply the new set of filters to the display object. filteredObject.filters = tempFilters; 确定滤镜索引 您需要知道要从数组中删除哪个滤镜,才能确定该滤镜的索引。您必须知道 (根据应用程序的设计方式)或计算出要删除的滤 镜的索引。 最佳方法是通过设计应用程序,确保要删除的滤镜始终位于滤镜组中的同一位置。例如,如果有一个显示对象先后应用了卷积 滤镜和投影滤镜,您希望删除投影滤镜而保留卷积滤镜,由于滤镜位于已知位置 (最顶层的滤镜),因此您可以提前知道应使 用哪种 Array 方法 (在本例中,使用 Array.pop() 删除投影滤镜)。 如果您要删除的滤镜始终属于某个特定类型,但不一定总在滤镜组中的同一位置,那么您可以检查该数组中每个滤镜的数据类 型,从而确定将要删除哪个滤镜。例如,下面的代码确定滤镜组中的哪个滤镜是发光滤镜,然后从该组中删除该滤镜。 // Example of removing a glow filter from a set of filters, where the //filter you want to remove is the only GlowFilter instance applied // to the filtered object. var tempFilters:Array = filteredObject.filters; // Loop through the filters to find the index of the GlowFilter instance. var glowIndex:int; var numFilters:int = tempFilters.length; for (var i:int = 0; i < numFilters; i++) { if (tempFilters[i] is GlowFilter) { glowIndex = i; break; } } // Remove the glow filter from the array. tempFilters.splice(glowIndex, 1); // Apply the new set of filters to the display object. filteredObject.filters = tempFilters; 在更为复杂的情况下 (比如要删除的滤镜是在运行时选定的),最好为滤镜数组保留一个单独的永久副本,用作主滤镜列表。 不论何时对滤镜组进行更改,均需更改主列表,然后按照显示对象的 filters 属性应用该滤镜数组。 例如,在下面的代码清单中,多个卷积滤镜应用于一个显示对象,以制造不同的视觉效果,随后在应用程序中删除其中一个滤 镜而保留其余滤镜。在本例中,代码保留滤镜数组的主副本以及对于要删除的滤镜的引用。查找并删除特定滤镜的方法与前面 的方法类似,但不是创建滤镜数组的临时副本,而是操作主副本,然后将其应用于显示对象。229ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 // Example of removing a filter from a set of // filters, where there may be more than one // of that type of filter applied to the filtered // object, and you only want to remove one. // A master list of filters is stored in a separate, // persistent Array variable. var masterFilterList:Array; // At some point, you store a reference to the filter you // want to remove. var filterToRemove:ConvolutionFilter; // ... assume the filters have been added to masterFilterList, // which is then assigned as the filteredObject.filters: filteredObject.filters = masterFilterList; // ... later, when it's time to remove the filter, this code gets called: // Loop through the filters to find the index of masterFilterList. var removeIndex:int = -1; var numFilters:int = masterFilterList.length; for (var i:int = 0; i < numFilters; i++) { if (masterFilterList[i] == filterToRemove) { removeIndex = i; break; } } if (removeIndex >= 0) { // Remove the filter from the array. masterFilterList.splice(removeIndex, 1); // Apply the new set of filters to the display object. filteredObject.filters = masterFilterList; } 在此方法(将存储的滤镜引用与滤镜数组中的项目进行比较以确定要删除哪个滤镜)中,必须 为滤镜数组保留一个单独的副本 — 如果将存储的滤镜引用与从显示对象的 filters 属性复制的临时数组中的元素进行比较,则代码将不起作用。这是因为在内部 将数组分配给 filters 属性时,运行时会为数组中的每个滤镜对象创建副本。这些副本 (而非原始对象)将应用于显示对象,而 在将 filters 属性读入临时数组时,临时数组包含对复制的滤镜对象的引用,而不是对原始滤镜对象的引用。因此,如果在上一 示例中尝试通过将 filterToRemove 与临时滤镜数组中的滤镜进行比较来确定其索引,则不会找到匹配的结果。 滤镜和对象变形 显示对象的边框矩形之外的任何过滤区域 (例如,投影)都不能视为可进行点击检测 (确定实例是否与其他实例重叠或交叉) 的表面。由于 DisplayObject 类的点击检测方法是基于矢量的,因此无法对位图结果执行点击检测。例如,如果您对按钮实例 应用斜角滤镜,则在该实例的斜角部分,点击检测不可用。 滤镜不支持缩放、旋转和倾斜;如果过滤的显示对象本身进行了缩放 (如果 scaleX 和 scaleY 不是 100%),则滤镜效果将不随 该实例缩放。这意味着,实例的原始形状将旋转、缩放或倾斜;而滤镜不随实例一起旋转、缩放或倾斜。 可以使用滤镜给实例添加动画,以形成理想的效果,或者嵌套实例并使用 BitmapData 类使滤镜动起来,以获得此效果。 滤镜和位图对象 对 BitmapData 对象应用滤镜时, cacheAsBitmap 属性会自动设置为 true。通过这种方式,滤镜实际上是应用于对象的副本而 不是原始对象。230ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 之后,会将此副本放在主显示 (原始对象)上,尽量接近最近的像素。如果原始位图的边框发生更改,则会从头重新创建过滤 的副本位图,而不是被伸展或扭曲。 如果清除了显示对象的所有滤镜, cacheAsBitmap 属性会重置为应用滤镜之前的值。 可用的显示滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 提供十个可用于显示对象和 BitmapData 对象的滤镜类: • 斜角滤镜 (BevelFilter 类) • 模糊滤镜 (BlurFilter 类) • 投影滤镜 (DropShadowFilter 类) • 发光滤镜 (GlowFilter 类) • 渐变斜角滤镜 (GradientBevelFilter 类) • 渐变发光滤镜 (GradientGlowFilter 类) • 颜色矩阵滤镜 (ColorMatrixFilter 类) • 卷积滤镜 (ConvolutionFilter 类) • 置换图滤镜 (DisplacementMapFilter 类) • 着色器滤镜 (ShaderFilter 类) 前六个滤镜是简单滤镜,可用于创建一种特定效果,并可以对效果进行某种程度的自定义。可以使用 ActionScript 应用这六 个滤镜,也可以在 Flash Professional 中使用 “ 滤镜 ” 面板将其应用于对象。因此,即使您要使用 ActionScript 应用滤镜,如 果有 Flash Professional,也可以使用可视界面快速尝试不同的滤镜和设置,以弄清楚如何创建所需的效果。 最后四个滤镜仅在 ActionScript 中可用。这些滤镜 (颜色矩阵滤镜、卷积滤镜、置换图滤镜和着色器滤镜)能够制造的效果 类型十分灵活。这些滤镜不是针对一种效果进行优化,而是具有强大的功能和灵活性。例如,如果为卷积滤镜的矩阵选择不同 的值,则它可用于创建模糊、浮雕、锐化、查找颜色边缘、变形等效果。 不管是简单滤镜还是复杂滤镜,每个滤镜都可以使用其属性进行自定义。通常,您有两种方法用于设置滤镜属性。所有滤镜都 允许通过向滤镜对象的构造函数传递参数值来设置属性。或者,不管您是否通过传递参数来设置滤镜属性,都可以在以后通过 设置滤镜对象的属性值来调整滤镜。多数示例代码清单都直接设置属性,以便更易于按照示例进行操作。不过,您通常可以通 过在滤镜对象的构造函数中以参数的形式传递值来获得同样的结果。有关每个滤镜及其属性和构造函数参数的更多详细信息, 请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中的 flash.filters 包列表。 斜角滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 BevelFilter 类可为过滤的对象添加 3D 斜角边缘。此滤镜可使对象的硬角或边缘具有硬角或边缘被凿削或呈斜面的效果。 BevelFilter 类属性允许您自定义斜角的外观。您可以设置加亮和阴影颜色、斜角边缘模糊、斜角角度和斜角边缘的位置,甚至 可以创建挖空效果。 以下示例加载外部图像并对它应用斜角滤镜。231ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 import flash.display.*; import flash.filters.BevelFilter; import flash.filters.BitmapFilterQuality; import flash.filters.BitmapFilterType; import flash.net.URLRequest; // Load an image onto the Stage. var imageLoader:Loader = new Loader(); var url:String = "http://www.helpexamples.com/flash/images/image3.jpg"; var urlReq:URLRequest = new URLRequest(url); imageLoader.load(urlReq); addChild(imageLoader); // Create the bevel filter and set filter properties. var bevel:BevelFilter = new BevelFilter(); bevel.distance = 5; bevel.angle = 45; bevel.highlightColor = 0xFFFF00; bevel.highlightAlpha = 0.8; bevel.shadowColor = 0x666666; bevel.shadowAlpha = 0.8; bevel.blurX = 5; bevel.blurY = 5; bevel.strength = 5; bevel.quality = BitmapFilterQuality.HIGH; bevel.type = BitmapFilterType.INNER; bevel.knockout = false; // Apply filter to the image. imageLoader.filters = [bevel]; 模糊滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 BlurFilter 类可使显示对象及其内容具有涂抹或模糊的效果。模糊效果可以用于产生对象不在焦点之内的视觉效果,也可以用 于模拟快速运动,比如运动模糊。通过将模糊滤镜的 quality 属性设置为非常低的值,可以模拟轻轻离开焦点的镜头效果。将 quality 属性设置为高会产生类似高斯模糊的平滑模糊效果。 以下示例使用 Graphics 类的 drawCircle() 方法创建一个圆形对象并对它应用模糊滤镜:232ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 import flash.display.Sprite; import flash.filters.BitmapFilterQuality; import flash.filters.BlurFilter; // Draw a circle. var redDotCutout:Sprite = new Sprite(); redDotCutout.graphics.lineStyle(); redDotCutout.graphics.beginFill(0xFF0000); redDotCutout.graphics.drawCircle(145, 90, 25); redDotCutout.graphics.endFill(); // Add the circle to the display list. addChild(redDotCutout); // Apply the blur filter to the rectangle. var blur:BlurFilter = new BlurFilter(); blur.blurX = 10; blur.blurY = 10; blur.quality = BitmapFilterQuality.MEDIUM; redDotCutout.filters = [blur]; 投影滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 投影给人一种目标对象上方有独立光源的印象。可以修改此光源的位置和强度,以产生各种不同的投影效果。 DropShadowFilter 类使用的算法与模糊滤镜的算法类似。主要区别是投影滤镜有更多的属性,您可以修改这些属性来模拟不 同的光源属性 (如 Alpha、颜色、偏移和亮度)。 投影滤镜还允许您对投影的样式应用自定义变形选项,包括内侧或外侧阴影和挖空 (也称为剪切块)模式。 以下代码创建方框 sprite 并对它应用投影滤镜: import flash.display.Sprite; import flash.filters.DropShadowFilter; // Draw a box. var boxShadow:Sprite = new Sprite(); boxShadow.graphics.lineStyle(1); boxShadow.graphics.beginFill(0xFF3300); boxShadow.graphics.drawRect(0, 0, 100, 100); boxShadow.graphics.endFill(); addChild(boxShadow); // Apply the drop shadow filter to the box. var shadow:DropShadowFilter = new DropShadowFilter(); shadow.distance = 10; shadow.angle = 25; // You can also set other properties, such as the shadow color, // alpha, amount of blur, strength, quality, and options for // inner shadows and knockout effects. boxShadow.filters = [shadow];233ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 发光滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 GlowFilter 类对显示对象应用加亮效果,使显示对象看起来像是被下方的灯光照亮,可创造出一种柔和发光效果。 与投影滤镜类似,发光滤镜包括的属性可修改光源的距离、角度和颜色,以产生各种不同效果。 GlowFilter 还有多个选项用于 修改发光样式,包括内侧或外侧发光和挖空模式。 以下代码使用 Sprite 类创建一个交叉对象并对它应用发光滤镜: import flash.display.Sprite; import flash.filters.BitmapFilterQuality; import flash.filters.GlowFilter; // Create a cross graphic. var crossGraphic:Sprite = new Sprite(); crossGraphic.graphics.lineStyle(); crossGraphic.graphics.beginFill(0xCCCC00); crossGraphic.graphics.drawRect(60, 90, 100, 20); crossGraphic.graphics.drawRect(100, 50, 20, 100); crossGraphic.graphics.endFill(); addChild(crossGraphic); // Apply the glow filter to the cross shape. var glow:GlowFilter = new GlowFilter(); glow.color = 0x009922; glow.alpha = 1; glow.blurX = 25; glow.blurY = 25; glow.quality = BitmapFilterQuality.MEDIUM; crossGraphic.filters = [glow]; 渐变斜角滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 GradientBevelFilter 类可对显示对象或 BitmapData 对象应用增强的斜角效果。在斜角上使用渐变颜色可以大大改善斜角的 空间深度,使边缘产生一种更逼真的三维外观效果。 以下代码使用 Shape 类的 drawRect() 方法创建一个矩形对象,并对它应用渐变斜角滤镜。234ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 import flash.display.Shape; import flash.filters.BitmapFilterQuality; import flash.filters.GradientBevelFilter; // Draw a rectangle. var box:Shape = new Shape(); box.graphics.lineStyle(); box.graphics.beginFill(0xFEFE78); box.graphics.drawRect(100, 50, 90, 200); box.graphics.endFill(); // Apply a gradient bevel to the rectangle. var gradientBevel:GradientBevelFilter = new GradientBevelFilter(); gradientBevel.distance = 8; gradientBevel.angle = 225; // opposite of 45 degrees gradientBevel.colors = [0xFFFFCC, 0xFEFE78, 0x8F8E01]; gradientBevel.alphas = [1, 0, 1]; gradientBevel.ratios = [0, 128, 255]; gradientBevel.blurX = 8; gradientBevel.blurY = 8; gradientBevel.quality = BitmapFilterQuality.HIGH; // Other properties let you set the filter strength and set options // for inner bevel and knockout effects. box.filters = [gradientBevel]; // Add the graphic to the display list. addChild(box); 渐变发光滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 GradientGlowFilter 类可对显示对象或 BitmapData 对象应用增强的发光效果。该效果可使您更好地控制发光颜色,因而可 产生一种更逼真的发光效果。另外,渐变发光滤镜还允许您对对象的内侧、外侧或上侧边缘应用渐变发光。 以下示例在舞台上绘制一个圆形,并对它应用渐变发光滤镜。当您进一步向右和向下移动鼠标时,会分别增加水平和垂直方向 的模糊量。此外,只要您在舞台上单击,就会增加模糊的强度。 import flash.events.MouseEvent; import flash.filters.BitmapFilterQuality; import flash.filters.BitmapFilterType; import flash.filters.GradientGlowFilter; // Create a new Shape instance. var shape:Shape = new Shape(); // Draw the shape. shape.graphics.beginFill(0xFF0000, 100); shape.graphics.moveTo(0, 0); shape.graphics.lineTo(100, 0); shape.graphics.lineTo(100, 100); shape.graphics.lineTo(0, 100); shape.graphics.lineTo(0, 0); shape.graphics.endFill(); // Position the shape on the Stage. addChild(shape); shape.x = 100; 235ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 shape.y = 100; // Define a gradient glow. var gradientGlow:GradientGlowFilter = new GradientGlowFilter(); gradientGlow.distance = 0; gradientGlow.angle = 45; gradientGlow.colors = [0x000000, 0xFF0000]; gradientGlow.alphas = [0, 1]; gradientGlow.ratios = [0, 255]; gradientGlow.blurX = 10; gradientGlow.blurY = 10; gradientGlow.strength = 2; gradientGlow.quality = BitmapFilterQuality.HIGH; gradientGlow.type = BitmapFilterType.OUTER; // Define functions to listen for two events. function onClick(event:MouseEvent):void { gradientGlow.strength++; shape.filters = [gradientGlow]; } function onMouseMove(event:MouseEvent):void { gradientGlow.blurX = (stage.mouseX / stage.stageWidth) * 255; gradientGlow.blurY = (stage.mouseY / stage.stageHeight) * 255; shape.filters = [gradientGlow]; } stage.addEventListener(MouseEvent.CLICK, onClick); stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); 示例:合并基本滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 以下代码示例使用与 Timer 合并的多个基本滤镜创建重复动作,以形成一种动画交通信号灯模拟效果。 import flash.display.Shape; import flash.events.TimerEvent; import flash.filters.BitmapFilterQuality; import flash.filters.BitmapFilterType; import flash.filters.DropShadowFilter; import flash.filters.GlowFilter; import flash.filters.GradientBevelFilter; import flash.utils.Timer; var count:Number = 1; var distance:Number = 8; var angleInDegrees:Number = 225; // opposite of 45 degrees var colors:Array = [0xFFFFCC, 0xFEFE78, 0x8F8E01]; var alphas:Array = [1, 0, 1]; var ratios:Array = [0, 128, 255]; var blurX:Number = 8; var blurY:Number = 8; var strength:Number = 1; var quality:Number = BitmapFilterQuality.HIGH; var type:String = BitmapFilterType.INNER; var knockout:Boolean = false; // Draw the rectangle background for the traffic light. var box:Shape = new Shape(); 236ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 box.graphics.lineStyle(); box.graphics.beginFill(0xFEFE78); box.graphics.drawRect(100, 50, 90, 200); box.graphics.endFill(); // Draw the 3 circles for the three lights. var stopLight:Shape = new Shape(); stopLight.graphics.lineStyle(); stopLight.graphics.beginFill(0xFF0000); stopLight.graphics.drawCircle(145,90,25); stopLight.graphics.endFill(); var cautionLight:Shape = new Shape(); cautionLight.graphics.lineStyle(); cautionLight.graphics.beginFill(0xFF9900); cautionLight.graphics.drawCircle(145,150,25); cautionLight.graphics.endFill(); var goLight:Shape = new Shape(); goLight.graphics.lineStyle(); goLight.graphics.beginFill(0x00CC00); goLight.graphics.drawCircle(145,210,25); goLight.graphics.endFill(); // Add the graphics to the display list. addChild(box); addChild(stopLight); addChild(cautionLight); addChild(goLight); // Apply a gradient bevel to the traffic light rectangle. var gradientBevel:GradientBevelFilter = new GradientBevelFilter(distance, angleInDegrees, colors, alphas, ratios, blurX, blurY, strength, quality, type, knockout); box.filters = [gradientBevel]; // Create the inner shadow (for lights when off) and glow // (for lights when on). var innerShadow:DropShadowFilter = new DropShadowFilter(5, 45, 0, 0.5, 3, 3, 1, 1, true, false); var redGlow:GlowFilter = new GlowFilter(0xFF0000, 1, 30, 30, 1, 1, false, false); var yellowGlow:GlowFilter = new GlowFilter(0xFF9900, 1, 30, 30, 1, 1, false, false); var greenGlow:GlowFilter = new GlowFilter(0x00CC00, 1, 30, 30, 1, 1, false, false); // Set the starting state of the lights (green on, red/yellow off). stopLight.filters = [innerShadow]; cautionLight.filters = [innerShadow]; goLight.filters = [greenGlow]; // Swap the filters based on the count value. function trafficControl(event:TimerEvent):void { if (count == 4) { count = 1; } switch (count) { case 1: stopLight.filters = [innerShadow]; cautionLight.filters = [yellowGlow]; goLight.filters = [innerShadow]; 237ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 break; case 2: stopLight.filters = [redGlow]; cautionLight.filters = [innerShadow]; goLight.filters = [innerShadow]; break; case 3: stopLight.filters = [innerShadow]; cautionLight.filters = [innerShadow]; goLight.filters = [greenGlow]; break; } count++; } // Create a timer to swap the filters at a 3 second interval. var timer:Timer = new Timer(3000, 9); timer.addEventListener(TimerEvent.TIMER, trafficControl); timer.start(); 颜色矩阵滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ColorMatrixFilter 类用于操作已应用滤镜的对象的颜色和 Alpha 值。它允许您进行饱和度更改、色相旋转 (将调色板从一个 颜色范围移动到另一个颜色范围)、将亮度更改为 Alpha,以及生成其他颜色操作效果,方法是使用一个颜色通道中的值,并 将这些值潜移默化地应用于其他通道。 从概念上来说,滤镜将逐一处理源图像中的像素,并将每个像素分为红、绿、蓝和 Alpha 组件。然后,用每个值乘以颜色矩阵 中提供的值,将结果加在一起以确定该像素将显示在屏幕上的最终颜色值。滤镜的 matrix 属性是一个由 20 个数字组成的数组, 用于计算最终颜色。有关用于计算颜色值的特定算法的详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参 考中描述 ColorMatrixFilter 类的 matrix 属性的条目。 卷积滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ConvolutionFilter 类可用于对 BitmapData 对象或显示对象应用广泛的图像变形,如模糊、边缘检测、锐化、浮雕和斜角。 从概念上来说,卷积滤镜会逐一处理源图像中的每个像素,并使用像素和它周围的像素的值来确定该像素的最终颜色。指定为 数值数组的矩阵可以指示每个特定邻近像素的值对最终结果值具有何种程度的影响。 最常用的矩阵类型是 3 x 3 矩阵。此矩阵包括九个值: N N N N P N NNN 对特定像素应用卷积滤镜时,会检查该像素本身的颜色值 (本示例中的 “P”)以及周围像素的值 (本示例中的 “N”)。而通过 设置矩阵中的值,可以指定特定像素在影响生成的图像方面所具有的优先级。 例如,使用卷积滤镜时应用的以下矩阵,会保持图像原样: 0 0 0 0 1 0 000238ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 图像保持不变的原因是,在决定最终像素颜色时,原始像素的值相对强度为 1,而周围像素的值相对强度为 0 (意味着它们的 颜色不影响最终图像)。 同样,下面的这个矩阵会使图像的像素向左移动一个像素: 0 0 0 0 0 1 000 请注意,在本例中,像素本身不影响最终图像上显示在该位置的像素的最终值,而只使用右侧的像素值来确定像素的结果值。 在 ActionScript 中,您可以通过组合一个包含值的 Array 实例和两个指定矩阵中行数和列数的属性来创建矩阵。以下示例加 载一个图像,完成加载该图像后,使用前面列表中的矩阵对该图像应用卷积滤镜: // Load an image onto the Stage. var loader:Loader = new Loader(); var url:URLRequest = new URLRequest("http://www.helpexamples.com/flash/images/image1.jpg"); loader.load(url); this.addChild(loader); function applyFilter(event:MouseEvent):void { // Create the convolution matrix. var matrix:Array = [0, 0, 0, 0, 0, 1, 0, 0, 0]; var convolution:ConvolutionFilter = new ConvolutionFilter(); convolution.matrixX = 3; convolution.matrixY = 3; convolution.matrix = matrix; convolution.divisor = 1; loader.filters = [convolution]; } loader.addEventListener(MouseEvent.CLICK, applyFilter); 此代码中没有明确显示使用除矩阵中 1 或 0 以外的值将会产生的效果。例如,同一矩阵中如果右侧位置的数字是 8 而不是 1, 则它会执行同样的动作 (向左移动像素)。此外,它还影响图像的颜色,使颜色加亮了 8 倍。这是因为最终像素颜色值的计算 方法是:用原始像素颜色乘以矩阵值,将这些值加在一起,再除以滤镜的 divisor 属性的值。请注意,在示例代码中,divisor 属 性设置为 1。通常,如果想让颜色的明亮度与原始图像保持基本相同,应让 divisor 等于矩阵值之和。因此,如果矩阵的值相加 为 8,并且除数为 1,结果图像将比原始图像明亮约 8 倍。 虽然此矩阵的效果不是很明显,但可以使用其他矩阵值以产生各种不同效果。以下是几组标准矩阵值集合,用于使用 3 x 3 矩 阵产生不同效果: • 基本模糊 (除数 5): 0 1 0 1 1 1 0 1 0 • 锐化 (除数 1): 0, -1, 0 -1, 5, -1 0, -1, 0 • 边缘检测 (除数 1): 0, -1, 0 -1, 4, -1 0, -1, 0239ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 • 浮雕效果 (除数 1): -2, -1, 0 -1, 1, 1 0, 1, 2 请注意,对于上述大部分效果, divisor 均为 1。这是因为负矩阵值加正矩阵值产生 1 ( 或边缘检测中的 0,但 divisor 属性 的值不能为 0)。 置换图滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 DisplacementMapFilter 类使用 BitmapData 对象 (称为置换图图像)的像素值在新对象上执行置换效果。通常,置换图图 像与将要应用滤镜的实际显示对象或 BitmapData 实例不同。置换效果包括置换经过过滤的图像中的像素,即让这些像素离开 各自原始位置一定距离。此滤镜可用于产生移位、扭曲或斑点效果。 应用于给定像素的置换位置和置换量由置换图图像的颜色值确定。使用滤镜时,除了指定置换图图像外,还要指定以下值,以 便控制置换图图像中计算置换的方式: • 映射点:过滤图像上的位置,在该点将应用置换滤镜的左上角。如果只想对图像的一部分应用滤镜,可以使用此值。 • X 组件:影响像素的 x 位置的置换图图像的颜色通道。 • Y 组件:影响像素的 y 位置的置换图图像的颜色通道。 • X 缩放比例:指定 x 轴置换强度的乘数值。 • Y 缩放比例:指定 y 轴置换强度的乘数值。 • 滤镜模式:确定在移开像素后形成的空白区域中要执行什么操作。在 DisplacementMapFilterMode 类中定义为常量的选 项可以显示原始像素 (滤镜模式 IGNORE)、从图像的另一侧环绕像素(滤镜模式 WRAP,这是默认设置)、使用最近的 移位像素 (滤镜模式 CLAMP)或用颜色填充空间 (滤镜模式 COLOR)。 若要了解置换图滤镜的工作原理,请查看下面的基本示例。在以下代码中,将加载一个图像,完成加载后使图像在舞台上居中 并对它应用置换图滤镜,使整个图像中的像素向左水平移位。240ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 import flash.display.BitmapData; import flash.display.Loader; import flash.events.MouseEvent; import flash.filters.DisplacementMapFilter; import flash.geom.Point; import flash.net.URLRequest; // Load an image onto the Stage. var loader:Loader = new Loader(); var url:URLRequest = new URLRequest("http://www.helpexamples.com/flash/images/image3.jpg"); loader.load(url); this.addChild(loader); var mapImage:BitmapData; var displacementMap:DisplacementMapFilter; // This function is called when the image finishes loading. function setupStage(event:Event):void { // Center the loaded image on the Stage. loader.x = (stage.stageWidth - loader.width) / 2; loader.y = (stage.stageHeight - loader.height) / 2; // Create the displacement map image. mapImage = new BitmapData(loader.width, loader.height, false, 0xFF0000); // Create the displacement filter. displacementMap = new DisplacementMapFilter(); displacementMap.mapBitmap = mapImage; displacementMap.mapPoint = new Point(0, 0); displacementMap.componentX = BitmapDataChannel.RED; displacementMap.scaleX = 250; loader.filters = [displacementMap]; } loader.contentLoaderInfo.addEventListener(Event.COMPLETE, setupStage); 用于定义置换的属性有: • 置换图位图:置换位图是由代码创建的新的 BitmapData 实例。它的尺寸与加载的图像的尺寸匹配 (因此会将置换应用于 整个图像)。用纯红色像素填充此实例。 • 映射点:将此值设置为点 0, 0,使置换再次应用于整个图像。 • X 组件:此值设置为常量 BitmapDataChannel.RED,表示置换图位图的红色值将决定沿着 x 轴置换像素的程度 (像素的移 动程度)。 • X 缩放比例:此值设置为 250。由于全部置换量 (与全红的置换图图像的距离)仅使图像置换很小的量 (大约为一个像素 的一半),因此,如果将此值设置为 1,图像只会水平移动 0.5 个像素。将此值设置为 250,图像将移动大约 125 个像素。 这些设置可使过滤图像的像素向左移动 250 个像素。移动的方向 (向左或向右)和移动量取决于置换图图像中的像素的颜色 值。从概念上来说,滤镜会逐一处理过滤图像的像素 (至少处理将应用滤镜的区域中的像素,在本例中指所有像素),并对每 个像素执行以下操作: 1 Flash Player 在置换图图像中查找相应的像素。例如,当滤镜计算过滤图像左上角像素的置换量时,会在置换图图像左上角 中查找像素。 2 Flash Player 确定置换图像素中指定颜色通道的值。在本例中, x 组件颜色通道是红色通道,因此滤镜将查看映射图像中该 问题像素所在位置处的红色通道所对应的值。由于置换图图像是纯红色的,所以像素的红色通道为 0xFF (即 255)。该值 将用作置换值。241ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 3 比较置换值和 “ 中间 ” 值(127,它是 0 和 255 之间的中间值)。如果置换值低于中间值,则像素正向移位(x 置换向右; y 置换向下)。另一方面,如果置换值高于中间值(如本示例),则像素负向移位(x 置换向左; y 置换向上)。为更精确起 见,滤镜会从 127 中减去置换值,结果 (正或负)即是应用的相对置换量。 4 最后,Flash Player 通过确定相对置换值所表示的完全置换量的百分比来确定实际置换量。在本例中,全红色意味着 100% 置换。然后用 x 缩放比例值或 y 缩放比例值乘以该百分比,以确定将应用的置换像素数。在本示例中,100% 乘以一个乘数 250 可以确定置换量 (大约为向左移动 125 个像素)。 因为没有为 y 分量和 y 缩放比例指定值,所以使用默认值 (不发生置换),这就是图像在垂直方向不移位的原因。 由于在本示例中使用了默认滤镜模式设置 WRAP,因此在像素向左移位时,会用移到图像左边缘以外的像素填充右侧空白区 域。您可以对此设置试用不同的值以查看不同的效果。例如,如果您在设置置换属性的代码部分中 (在 loader.filters = [displacementMap] 行之前)添加以下一行内容,则会使图像在舞台上产生涂抹的效果: displacementMap.mode = DisplacementMapFilterMode.CLAMP; 下面是一个更为复杂的示例,代码清单中使用置换图滤镜在图像上创建放大镜效果: import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.display.GradientType; import flash.display.Loader; import flash.display.Shape; import flash.events.MouseEvent; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.geom.Matrix; import flash.geom.Point; import flash.net.URLRequest; // Create the gradient circles that will together form the // displacement map image var radius:uint = 50; var type:String = GradientType.LINEAR; var redColors:Array = [0xFF0000, 0x000000]; var blueColors:Array = [0x0000FF, 0x000000]; var alphas:Array = [1, 1]; var ratios:Array = [0, 255]; var xMatrix:Matrix = new Matrix(); xMatrix.createGradientBox(radius * 2, radius * 2); var yMatrix:Matrix = new Matrix(); yMatrix.createGradientBox(radius * 2, radius * 2, Math.PI / 2); var xCircle:Shape = new Shape(); xCircle.graphics.lineStyle(0, 0, 0); xCircle.graphics.beginGradientFill(type, redColors, alphas, ratios, xMatrix); xCircle.graphics.drawCircle(radius, radius, radius); var yCircle:Shape = new Shape(); yCircle.graphics.lineStyle(0, 0, 0); yCircle.graphics.beginGradientFill(type, blueColors, alphas, ratios, yMatrix); yCircle.graphics.drawCircle(radius, radius, radius); // Position the circles at the bottom of the screen, for reference. this.addChild(xCircle); xCircle.y = stage.stageHeight - xCircle.height; this.addChild(yCircle); yCircle.y = stage.stageHeight - yCircle.height; yCircle.x = 200; 242ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 // Load an image onto the Stage. var loader:Loader = new Loader(); var url:URLRequest = new URLRequest("http://www.helpexamples.com/flash/images/image1.jpg"); loader.load(url); this.addChild(loader); // Create the map image by combining the two gradient circles. var map:BitmapData = new BitmapData(xCircle.width, xCircle.height, false, 0x7F7F7F); map.draw(xCircle); var yMap:BitmapData = new BitmapData(yCircle.width, yCircle.height, false, 0x7F7F7F); yMap.draw(yCircle); map.copyChannel(yMap, yMap.rect, new Point(0, 0), BitmapDataChannel.BLUE, BitmapDataChannel.BLUE); yMap.dispose(); // Display the map image on the Stage, for reference. var mapBitmap:Bitmap = new Bitmap(map); this.addChild(mapBitmap); mapBitmap.x = 400; mapBitmap.y = stage.stageHeight - mapBitmap.height; // This function creates the displacement map filter at the mouse location. function magnify():void { // Position the filter. var filterX:Number = (loader.mouseX) - (map.width / 2); var filterY:Number = (loader.mouseY) - (map.height / 2); var pt:Point = new Point(filterX, filterY); var xyFilter:DisplacementMapFilter = new DisplacementMapFilter(); xyFilter.mapBitmap = map; xyFilter.mapPoint = pt; // The red in the map image will control x displacement. xyFilter.componentX = BitmapDataChannel.RED; // The blue in the map image will control y displacement. xyFilter.componentY = BitmapDataChannel.BLUE; xyFilter.scaleX = 35; xyFilter.scaleY = 35; xyFilter.mode = DisplacementMapFilterMode.IGNORE; loader.filters = [xyFilter]; } // This function is called when the mouse moves. If the mouse is // over the loaded image, it applies the filter. function moveMagnifier(event:MouseEvent):void { if (loader.hitTestPoint(loader.mouseX, loader.mouseY)) { magnify(); } } loader.addEventListener(MouseEvent.MOUSE_MOVE, moveMagnifier);243ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 代码首先生成两个渐变圆,它们合并在一起构成置换图图像。红色圆创建 x 轴置换 (xyFilter.componentX = BitmapDataChannel.RED),蓝色圆创建 y 轴置换 (xyFilter.componentY = BitmapDataChannel.BLUE)。为帮助您理解置换图图 像的外观,代码向屏幕底部添加了原始圆形以及合并后作为置换图图像的圆形。 然后,代码加载一个图像,当鼠标移动时,将置换滤镜应用于鼠标下方的图像部分。用作置换图图像的渐变圆使置换区域从指 针处向外扩展。请注意,置换图图像的灰色区域不会发生置换。灰色为 0x7F7F7F。该灰色的蓝色和红色通道与这些颜色通道中 的中间色度完全匹配,因此在置换图图像的灰色区域不会发生置换。同样,在圆的中心也不会发生置换。由于蓝色和红色是引 起置换的颜色,虽然颜色中没有灰色,但该颜色的蓝色通道和红色通道与中度灰的蓝色通道和红色通道完全相同,因此该处不 发生置换。 着色器滤镜 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 ShaderFilter 类可使用定义为 Pixel Bender 着色器的自定义滤镜效果。由于该滤镜效果是以 Pixel Bender 着色器形式编写 的,因此可完全自定义。过滤内容将作为图像输入传递给着色器,着色器操作的结果就是滤镜结果。 注: 从 Flash Player 10 和 Adobe AIR 1.5 开始,在 ActionScript 中提供着色器滤镜。 若要对某个对象应用着色器滤镜,首先应创建一个表示要使用的 Pixel Bender 着色器的 Shader 实例。有关 Shader 实例创建 过程以及如何指定输入图像和参数值的详细信息,请参阅第 251 页的 “ 使用 Pixel Bender 着色器 ”。 将着色器用作滤镜时,请记住以下三个要点: • 必须将着色器定义为至少接受一个输入图像。 • 将过滤对象 (为之应用滤镜的显示对象或 BitmapData 对象)作为第一个输入图像值传递给着色器。因此,不要为第一个 图像输入手动指定值。 • 如果着色器定义了多个输入图像,则必须手动指定其他输入(即,为属于 Shader 实例的任何 ShaderInput 实例设置 input 属性)。 创建着色器的 Shader 对象后,即创建了一个 ShaderFilter 实例。这就是使用方法与其他所有滤镜相同的实际滤镜对象。若要 创建使用 Shader 对象的 ShaderFilter,请调用 ShaderFilter() 构造函数,并将 Shader 对象作为参数传递,如下所示: var myFilter:ShaderFilter = new ShaderFilter(myShader); 有关使用着色器滤镜的完整示例,请参阅第 266 页的 “ 使用着色器作为滤镜 ”。244ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 筛选显示对象示例:Filter Workbench Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Filter Workbench 提供了一个用户界面,用于对图像和其他可视内容应用不同的滤镜以及查看结果代码,这些代码可用于在 ActionScript 中生成相同的效果。除了提供试验滤镜的工具外,此应用程序还展示了以下技巧: • 创建各种滤镜的实例 • 对显示对象应用多种滤镜 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。可以在 Samples/FilterWorkbench 文件夹中找到 Filter Workbench 应用程序文件。该应用程序包含以下文件: 文件 说明 com/example/programmingas3/filterWorkbench/FilterWorkbenchController.as 提供应用程序主要功能的类,主要功能包括切换要应用 滤镜的内容以及将滤镜应用于内容。 com/example/programmingas3/filterWorkbench/IFilterFactory.as 用来定义由各滤镜工厂类所实现的常用方法的接口。此 接口定义 FilterWorkbenchController 类用来与各个滤 镜工厂类交互的常见功能。 在文件夹 com/example/programmingas3/filterWorkbench/ 中: BevelFactory.as BlurFactory.as ColorMatrixFactory.as ConvolutionFactory.as DropShadowFactory.as GlowFactory.as GradientBevelFactory.as GradientGlowFactory.as 类集,每个类都实现 IFilterFactory 接口。每个类均可 为某一类型的滤镜提供创建和设置值的功能。应用程序 中的滤镜属性面板使用这些工厂类来创建其特定滤镜的 实例, FilterWorkbenchController 类将检索这些实例 并将它们应用于图像内容。 com/example/programmingas3/filterWorkbench/IFilterPanel.as 定义某些类 (这些类定义用于操作应用程序中滤镜值的 用户界面面板)所实现的常见方法的接口。 com/example/programmingas3/filterWorkbench/ColorStringFormatter.as 实用程序类,包含将数字颜色值转换为十六进制字符串 格式的方法 com/example/programmingas3/filterWorkbench/GradientColor.as 作为值对象的类,此类将与 GradientBevelFilter 和 GradientGlowFilter 中各颜色相关联的三个值 (颜色、 Alpha 和比例)合并到单个对象中 用户界面 (Flex) FilterWorkbench.mxml 定义应用程序用户界面的主要文件。 flexapp/FilterWorkbench.as 为主应用程序用户界面提供功能的类;此类用作应用程 序 MXML 文件的代码隐藏类。245ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 在 flexapp/filterPanels 文件夹中: BevelPanel.mxml BlurPanel.mxml ColorMatrixPanel.mxml ConvolutionPanel.mxml DropShadowPanel.mxml GlowPanel.mxml GradientBevelPanel.mxml GradientGlowPanel.mxml MXML 组件集,为各面板 (用于为单个滤镜设置选项) 提供功能。 flexapp/ImageContainer.as 作为屏幕上已加载图像的容器的显示对象 flexapp/controls/BGColorCellRenderer.as 用于更改 DataGrid 组件中单元格的背景颜色的自定义 单元格渲染器 flexapp/controls/QualityComboBox.as 自定义控件,负责定义可用于多个滤镜面板中 “ 品质 ” 设置的组合框。 flexapp/controls/TypeComboBox.as 自定义控件,负责定义可用于多个滤镜面板中 “ 类型 ” 设置的组合框。 用户界面 (Flash) FilterWorkbench.fla 定义应用程序用户界面的主要文件。 flashapp/FilterWorkbench.as 为主应用程序用户界面提供功能的类;此类用作应用程 序 FLA 文件的文档类。 在 flashapp/filterPanels 文件夹中: BevelPanel.as BlurPanel.as ColorMatrixPanel.as ConvolutionPanel.as DropShadowPanel.as GlowPanel.as GradientBevelPanel.as GradientGlowPanel.as 类集,为各面板 (用于为单个滤镜设置选项)提供功 能。 对于每个类而言,在主应用程序 FLA 文件库中,还有一 个关联的 MovieClip 元件,其名称与类的名称相匹配 (例如, “BlurPanel” 元件链接到 BlurPanel.as 中定义 的类)。构成用户界面的组件在这些元件中进行定位和命 名。 flashapp/ImageContainer.as 作为屏幕上已加载图像的容器的显示对象 flashapp/BGColorCellRenderer.as 用于更改 DataGrid 组件中单元格的背景颜色的自定义 单元格渲染器 flashapp/ButtonCellRenderer.as 用于将 Button 组件包含在 DataGrid 组件的单元格中的 自定义单元格渲染器 文件 说明246ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 试验 ActionScript 滤镜 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Filter Workbench 应用程序旨在帮助您试验各种滤镜效果,并为该效果生成相关的 ActionScript 代码。使用该应用程序,您 可以从包含可视内容 (包括位图图像和 Flash 创建的动画)的三种不同文件中进行选择,并可采用单独或与其他滤镜相结合的 方式,将八种不同的 ActionScript 滤镜应用于选定的图像。此应用程序包含以下滤镜: • 斜角 (flash.filters.BevelFilter) • 模糊 (flash.filters.BlurFilter) • 颜色矩阵 (flash.filters.ColorMatrixFilter) • 卷积 (flash.filters.ConvolutionFilter) • 投影 (flash.filters.DropShadowFilter) • 发光 (flash.filters.GlowFilter) • 渐变斜角 (flash.filters.GradientBevelFilter) • 渐变发光 (flash.filters.GradientGlowFilter) 套用滤镜的图像内容 com/example/programmingas3/filterWorkbench/ImageType.as 此类用作值对象,它包含应用程序可加载并对其应用滤 镜的单个图像文件的类型和 URL。此类还包含一组代表 实际可用图像文件的常量。 images/sampleAnimation.swf images/sampleImage1.jpg images/sampleImage2.jpg 应用程序中应用滤镜的图像和其他可视内容。 文件 说明247ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 用户选定图像并将滤镜应用于图像后,应用程序将显示一个带有用于设置选定滤镜特定属性的控件的面板。例如,下列图像显 示的是已选择 “ 斜角 ” 滤镜的应用程序: 如果用户调整滤镜属性,则预览将实时更新。用户还可以应用多个滤镜,方法是:自定义一个滤镜,单击 “ 应用 ” 按钮;自定 义另一个滤镜,单击 “ 应用 ” 按钮,以此类推。 应用程序的滤镜面板具有一些功能和限制: • 颜色矩阵滤镜包含一组用于直接操作常用图像属性 (包括亮度、对比度、饱和度和色相)的控件。另外,可以指定自定义 颜色矩阵值。 • 卷积滤镜只有在使用 ActionScript 时才可用,此滤镜包含一组常用的卷积矩阵值,也可指定自定义值。但是,虽然 ConvolutionFilter 类可以接受任意大小的矩阵,但 Filter Workbench 应用程序使用的是固定的 3 x 3 矩阵,这是最常用 的滤镜大小。 • 置换图滤镜和着色器滤镜仅在 ActionScript 中可用,在 Filter Workbench 应用程序中不可用。 创建滤镜实例 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Filter Workbench 应用程序包含一个类集,各可用滤镜均有一个对应的类,各面板用这些类来创建滤镜。用户选定滤镜后, 与滤镜面板相关联的 ActionScript 代码就将创建相应滤镜工厂类的实例。(这些类称为工厂类,因为其用途在于创建其他对象 的实例,这与实际工厂创建各产品极为相似) 只要用户更改面板上的属性值,面板的代码就会调用工厂类中的相应方法。各工厂类包含面板用于创建相应滤镜实例的特定方 法。例如,如果用户选择 “ 模糊 ” 滤镜,则应用程序将创建 BlurFactory 实例。BlurFactory 类包含一个 modifyFilter() 方法, 该方法接受三个参数:blurX、 blurY 和 quality,这三个参数一起用于创建所需的 BlurFilter 实例:248ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 private var _filter:BlurFilter; public function modifyFilter(blurX:Number = 4, blurY:Number = 4, quality:int = 1):void { _filter = new BlurFilter(blurX, blurY, quality); dispatchEvent(new Event(Event.CHANGE)); } 另一方面,如果用户选择 “ 卷积 ” 滤镜,因为该滤镜允许更大的灵活性,所以需要控制的属性就会更多。在 ConvolutionFactory 类中,如果用户在滤镜面板上选择不同的值,则将调用以下代码: private var _filter:ConvolutionFilter; public function modifyFilter(matrixX:Number = 0, matrixY:Number = 0, matrix:Array = null, divisor:Number = 1.0, bias:Number = 0.0, preserveAlpha:Boolean = true, clamp:Boolean = true, color:uint = 0, alpha:Number = 0.0):void { _filter = new ConvolutionFilter(matrixX, matrixY, matrix, divisor, bias, preserveAlpha, clamp, color, alpha); dispatchEvent(new Event(Event.CHANGE)); } 请注意,在各例中,如果滤镜值发生变化,则工厂对象将调度 Event.CHANGE 事件,从而向侦听器 通知滤镜的值已经改变。 将滤镜实际应用于过滤内容的 FilterWorkbenchController 类将侦听该事件,以确定何时需检索滤镜的新副本并将其重新应 用于过滤的内容。 FilterWorkbenchController 类无需知道各滤镜工厂类的特定详细信息,它只需知道滤镜已更改,并能够访问滤镜副本即可。 为支持此目的,应用程序包含了一个 IFilterFactory 接口,该接口定义滤镜工厂类需提供的行为,以便应用程序的 FilterWorkbenchController 实例能够完成自己的工作。 IFilterFactory 定义在 FilterWorkbenchController 类中使用的 getFilter() 方法: function getFilter():BitmapFilter; 请注意,getFilter() 接口方法定义指定该方法返回一个 BitmapFilter 实例,而非特定类型的滤镜。BitmapFilter 类不定义特定 类型的滤镜,而是用来构建所有滤镜类的基类。各滤镜工厂类定义 getFilter() 方法的特定实现,此时将返回对所创建滤镜对象 的引用。例如,以下就是 ConvolutionFactory 类源代码的缩写版本: public class ConvolutionFactory extends EventDispatcher implements IFilterFactory { // ------- Private vars ------- private var _filter:ConvolutionFilter; ... // ------- IFilterFactory implementation ------- public function getFilter():BitmapFilter { return _filter; } ... } ConvolutionFactory 类在实现 getFilter() 方法时将返回一个 ConvolutionFilter 实例,尽管调用 getFilter() 的任何对象无需知 道此返回结果。根据 ConvolutionFactory 所遵循的 getFilter() 方法的定义,此方法必须返回任意 BitmapFilter 实例,这些实 例可能是任意 ActionScript 滤镜类的实例。249ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 将滤镜应用于显示对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如前所述, Filter Workbench 应用程序使用 FilterWorkbenchController 类的实例 (下文称为 “ 控制器实例 ”),该实例执 行将滤镜应用于所选可视对象的实际任务。控制器实例必须首先知道滤镜需应用于哪些图像或可视内容,然后才能应用滤镜。 用户选定图像后,应用程序将调用 FilterWorkbenchController 类中的 setFilterTarget() 方法,传入在 ImageType 类中定义 的一个常量: public function setFilterTarget(targetType:ImageType):void { ... _loader = new Loader(); ... _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, targetLoadComplete); ... } 控制器实例使用该信息来加载指定的文件,并将所加载的文件存储在一个名为 _currentTarget 的实例变量中: private var _currentTarget:DisplayObject; private function targetLoadComplete(event:Event):void { ... _currentTarget = _loader.content; ... } 用户选择滤镜后,应用程序将调用控制器实例的 setFilter() 方法,为控制器提供对相关滤镜工厂对象的引用,此引用存储在名 为 _filterFactory 的实例变量中。 private var _filterFactory:IFilterFactory; public function setFilter(factory:IFilterFactory):void { ... _filterFactory = factory; _filterFactory.addEventListener(Event.CHANGE, filterChange); } 请注意,正如上文所说明的那样,控制器实例并不知道为其提供的滤镜工厂实例的具体数据类型,它只知道对象实现 IFilterFactory 实例,这意味着它具有 getFilter() 方法,并可在滤镜更改时调度 change (Event.CHANGE) 事件。 如果用户改变滤镜面板中的滤镜属性,则控制器实例将通过滤镜工厂的 change 事件发现滤镜已发生更改,该事件调用控制器实 例的 filterChange() 方法。而该方法又将调用 applyTemporaryFilter() 方法:250ACTIONSCRIPT 3.0 开发人员指南 过滤显示对象 上次更新 2014/12/1 private function filterChange(event:Event):void { applyTemporaryFilter(); } private function applyTemporaryFilter():void { var currentFilter:BitmapFilter = _filterFactory.getFilter(); // Add the current filter to the set temporarily _currentFilters.push(currentFilter); // Refresh the filter set of the filter target _currentTarget.filters = _currentFilters; // Remove the current filter from the set // (This doesn't remove it from the filter target, since // the target uses a copy of the filters array internally.) _currentFilters.pop(); } 将滤镜应用于显示对象的工作在 applyTemporaryFilter() 方法中进行。首先,控制器将通过调用滤镜工厂的 getFilter() 方法来检 索对滤镜对象的引用。 var currentFilter:BitmapFilter = _filterFactory.getFilter(); 控制器实例有一个名为 _currentFilters 的数组实例变量,所有曾应用于显示对象的滤镜均存储在该变量中。下一步就是将新近 更新的滤镜添加到该数组: _currentFilters.push(currentFilter); 然后,代码将滤镜数组分配给显示对象的 filters 属性,这会将滤镜实际应用于图像: _currentTarget.filters = _currentFilters; 最后,由于此最近添加的滤镜仍旧是 “ 工作 ” 滤镜,不应将其永久应用于显示对象,因此将其从 _currentFilters 数组中删除: _currentFilters.pop(); 将此滤镜从数组中删除并不会影响已过滤的显示对象,因为在将滤镜数组分配给 filters 属性时,显示对象将生成滤镜数组的副 本,而且显示对象使用的是内部数组而非原始数组。因此,对滤镜数组所做的任何更改均不会影响显示对象,直至数组被再次 分配给显示对象的 filters 属性。251 上次更新 2014/12/1 第 15 章 : 使用 Pixel Bender 着色器 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 利用 Adobe Pixel Bender 工具包,开发人员可以编写用于创建图形效果、执行其他图像和数据处理的着色器。Pixel Bender 字节码可以在 ActionScript 中执行,从而将效果应用于图像数据或可视内容。通过在 ActionScript 中使用 Pixel Bender 着色 器,不仅可以运用 ActionScript 的内置功能,而且还可以创建自定义的视觉效果并执行数据处理。 注: 从 Flash Player 10 和 Adobe AIR 1.5 开始支持 Pixel Bender。在 GPU 呈现下不支持 Pixel Bender 混合、滤镜和填充。 更多帮助主题 Adobe Pixel Bender 技术中心 Pixel Bender 开发人员指南 Pixel Bender 参考 flash.display.Shader flash.filters.ShaderFilter 针对 Flash 的 Pixel Bender 基础知识 针对 Flex 的 Pixel Bender 基础知识 Pixel Bender 着色器基础知识 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 Adobe Pixel Bender 是一种编程语言,用于创建或操作图像内容。使用 Pixel Bender (也称为着色器)创建内核。着色器定 义了一个可对图像的每个像素单独执行的单一函数。对该函数的每次调用都将得到图像中该像素坐标处的输出颜色。可通过指 定输入图像和参数值来自定义该操作。在着色器的单次执行中,输入值和参数值是不变的。唯一发生变化的是像素 (其颜色是 函数调用的结果)的坐标。 对多个输出像素坐标调用着色器函数时,将尽可能采用并行方式。这样会改进着色器性能,提供高性能的处理能力。 在 ActionScript 中,可使用着色器轻松地创建三种类型的效果: • 绘制填充 • 混合模式 • 滤镜 着色器也可以按独立模式执行。使用独立模式时,将直接访问着色器的结果,而非预先指定着色器的用途。结果可以按图像数 据或者二进制或数值数据的形式访问。该数据完全不必是图像数据。这样一来,您可以为着色器输入一组数据。着色器将处理 该数据,然后您可以访问着色器返回的结果数据。 从 Flash Player 10 和 Adobe AIR 1.5 开始支持 Pixel Bender。在 GPU 呈现下不支持 Pixel Bender 混合、滤镜和填充。在 移动设备上, Pixel Bender 着色器在 CPU 呈现下运行。但是,其性能与在桌面计算机上相差甚远。许多着色器程序每秒只能 执行几个帧。252ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 重要概念和术语 以下参考列表包含创建和使用 Pixel Bender 着色器时会遇到的重要术语: 内核 对于 Pixel Bender,内核就相当于着色器。通过 Pixel Bender,您的代码定义了一个内核,它定义了可对图像的每个像 素单独执行的单一函数。 Pixel Bender 字节码 编译 Pixel Bender 内核时,它会转换为 Pixel Bender 字节码。在运行时访问并执行字节码。 Pixel Bender 语言 用于创建 Pixel Bender 内核的编程语言。 Pixel Bender 工具包 用于根据 Pixel Bender 源代码创建 Pixel Bender 字节码文件的应用程序。您可以使用该工具包编写、测 试和编译 Pixel Bender 源代码。 Shader 对于此文档而言,着色器是用 Pixel Bender 语言编写的一组功能。着色器的代码会创建视觉效果或执行计算。在任一 情况下,着色器都返回一组数据 (通常为图像的像素)。着色器在每个数据点上执行的操作都相同,唯一的区别是输出像素的 坐标。着色器不是用 ActionScript 编写的。它用 Pixel Bender 语言编写,并编译为 Pixel Bender 字节代码。着色器可在编译 时嵌入 SWF 文件,也可在运行时作为外部文件加载。无论采用上述哪一种方式,都要在 ActionScript 中访问着色器,方法是 先创建一个 Shader 对象,然后将其链接到着色器字节代码。 着色器输入 一种复杂的输入,通常为位图图像数据,提供给着色器供其计算之用。对于着色器中定义的每个输入变量,着色器 的整个执行过程都使用单一变量值 (即,一个图像或一组二进制数据)。 着色器参数 提供给着色器的单个值 (或限定的一组值),供着色器进行计算用。着色器的每次执行中都会定义各个参数值,该 值在着色器的整个执行过程中保持不变。 完成代码示例 您可能想测试提供的示例代码列表。测试代码包括运行代码,并在创建的 SWF 中查看结果。所有示例都使用绘图 API 创建内 容,这类 API 使用着色器效果,或由该效果进行修改。 大多数示例代码清单都包含两个部分。一部分是此示例中所用着色器的 Pixel Bender 源代码。您必须首先使用 Pixel Bender 工具包将源代码编译成 Pixel Bender 字节代码文件。请遵循以下步骤创建 Pixel Bender 字节代码文件: 1 打开 Adobe Pixel Bender 工具包。如有必要,从 “ 生成 ” 菜单中选择 “ 打开 Flash Player 警告和错误 ”。 2 复制 Pixel Bender 代码清单,然后粘贴到 Pixel Bender 工具包的代码编辑器窗格中。 3 从 “ 文件 ” 菜单中,选择 “ 为 Flash Player 导出内核滤镜 ”。 4 将 Pixel Bender 字节代码文件保存到 Flash 文档所在的目录。文件名应与示例说明中指定的名称一致。 每个示例的 ActionScript 部分都编写为一个类文件。要在 Flash Professional 中测试示例,请执行下列操作: 1 创建一个空的 Flash 文档并将它保存到您的计算机上。 2 创建一个新的 ActionScript 文件,并将它保存到 Flash 文档所在的目录中。文件名应与代码清单中的类的名称一致。例 如,如果代码清单定义了一个名为 MyApplication 的类,则使用 MyApplication.as 名称保存 ActionScript 文件。 3 将代码清单复制到 ActionScript 文件中并保存该文件。 4 在 Flash 文档中,单击舞台或工作区的空白部分,以激活文档的 “ 属性 ” 检查器。 5 在 “ 属性 ” 检查器的 “ 文档类 ” 字段中,输入您从文本中复制的 ActionScript 类的名称。 6 使用 “ 控制 ”>“ 测试影片 ” 来运行程序 您将在预览窗口中看到示例的结果。 第 939 页的 “ 如何使用 ActionScript 示例 ” 中详细介绍了测试示例代码清单的方法。253ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 加载或嵌入着色器 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在 ActionScript 中使用 Pixel Bender 着色器的第一步是在 ActionScript 代码中访问着色器。因为着色器是用 Adobe Pixel Bender 工具包创建并以 Pixel Bender 语言编写的,所以不能在 ActionScript 中直接访问。您需要创建 Shader 类的一个实 例,用于向 ActionScript 表示 Pixel Bender 着色器。通过 Shader 对象可以查明着色器的有关信息,如着色器是否需要参数或 输入图像值。将 Shader 对象传递给其他对象即可实际使用着色器。例如,若要将着色器用作滤镜,可将 Shader 对象分配给 ShaderFilter 对象的 shader 属性。若要将着色器用作绘制填充,可将 Shader 对象作为参数传递给 Graphics.beginShaderFill() 方法。 ActionScript 代码可以通过两种方式访问由 Adobe Pixel Bender 工具包创建的着色器 (.pbj 文件): • 在运行时加载:可以使用 URLLoader 对象将着色器文件作为外部资源进行加载。这种方法类似于加载外部资源 (如文本 文件)。下面的示例演示如何在运行时加载着色器字节码文件并将其链接到一个 Shader 实例: var loader:URLLoader = new URLLoader(); loader.dataFormat = URLLoaderDataFormat.BINARY; loader.addEventListener(Event.COMPLETE, onLoadComplete); loader.load(new URLRequest("myShader.pbj")); var shader:Shader; function onLoadComplete(event:Event):void { // Create a new shader and set the loaded data as its bytecode shader = new Shader(); shader.byteCode = loader.data; // You can also pass the bytecode to the Shader() constructor like this: // shader = new Shader(loader.data); // do something with the shader } • 嵌入在 SWF 文件中:使用 [Embed] 元数据标签可以在编译时将着色器文件嵌入在 SWF 文件中。只有在使用 Flex SDK 编 译 SWF 文件时, [Embed] 元数据标签才可用。 [Embed] 标签的 source 参数指向着色器文件,其 mimeType 参数为 "application/octet-stream",如以下示例中所示: [Embed(source="myShader.pbj", mimeType="application/octet-stream")] var MyShaderClass:Class; // ... // create a shader and set the embedded shader as its bytecode var shader:Shader = new Shader(); shader.byteCode = new MyShaderClass(); // You can also pass the bytecode to the Shader() constructor like this: // var shader:Shader = new Shader(new MyShaderClass()); // do something with the shader 在任何一种情况下,都可以将原始着色器字节码 (URLLoader.data 属性或 [Embed] 数据类的实例)链接到 Shader 实例。如以 上示例所示,可以通过两种方式将字节码分配给 Shader 实例。可以将着色器字节代码作为参数传递到 Shader() 构造函数。或 者,可以将其设置为 Shader 实例的 byteCode 属性。 在创建 Pixel Bender 着色器并将其链接到 Shader 对象后,即可使用着色器以多种方式创建效果。您可以将着色器用作滤镜、 混合模式、位图填充,也可以用于位图或其他数据的独立处理。您还可以使用 Shader 对象的 data 属性访问着色器的元数据、 指定输入图像以及设置参数值。254ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 访问着色器元数据 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在创建 Pixel Bender 着色器内核时,作者可以在 Pixel Bender 源代码中指定着色器的相关元数据。在 ActionScript 中使用着 色器时,可以检查着色器和提取其元数据。 在创建 Shader 实例并将其链接到 Pixel Bender 着色器时,会创建一个包含着色器相关数据的 ShaderData 对象并将该对象存 储在 Shader 对象的 data 属性中。ShaderData 类不定义自身的任何属性。但是,对于在着色器源代码中定义的每个元数据值, 都会在运行时将一个属性动态添加到 ShaderData 对象。为每个属性提供的名称与在元数据中指定的名称相同。例如,假设 Pixel Bender 着色器的源代码包括下面的元数据定义: namespace : "Adobe::Example"; vendor : "Bob Jones"; version : 1; description : "Creates a version of the specified image with the specified brightness."; 则为该着色器创建 ShaderData 对象时将使用以下属性和值: • namespace (字符串):"Adobe::Example" • vendor (字符串):"Bob Jones" • version (字符串):"1" • description (字符串):"Creates a version of the specified image with the specified brightness" 因为元数据属性是动态添加到 ShaderData 对象的,所以可以使用 for..in 循环检查 ShaderData 对象。通过这种方法,可以确 定着色器是否具有元数据以及元数据是何值。除了元数据属性之外, ShaderData 对象还可能具有表示着色器中定义的输入和 参数的属性。在使用 for..in 循环检查 ShaderData 对象时,检查每个属性的数据类型以确定属性是输入 (ShaderInput 实 例)、参数(ShaderParameter 实例)还是元数据值 (String 实例)。下面的示例演示如何使用 for..in 循环检查着色器的 data 属性的动态属性。每个元数据值都会添加到一个名为 metadata 的 Vector 实例。请注意,此示例假设已创建了名为 myShader 的 Shader 实例: var shaderData:ShaderData = myShader.data; var metadata:Vector. = new Vector.(); for (var prop:String in shaderData) { if (!(shaderData[prop] is ShaderInput) && !(shaderData[prop] is ShaderParameter)) { metadata[metadata.length] = shaderData[prop]; } } // do something with the metadata 有关增加着色器输入和参数提取的此示例版本,请参阅第 255 页的 “ 识别着色器输入和参数 ”。有关输入和参数属性的详细信 息,请参阅第 254 页的 “ 指定着色器输入和参数值 ”。 指定着色器输入和参数值 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 许多 Pixel Bender 着色器定义为使用一个或多个在着色器处理中使用的输入图像。例如,一种常见情况是,着色器接受一个源 图像,然后输出应用了特定效果的该图像。根据着色器的使用方式,可以自动指定输入值,也可能需要明确提供值。同样,许 多着色器指定用于自定义着色器输出的参数。在使用着色器之前,还必须为每个参数明确设置一个值。255ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 使用 Shader 对象的 data 属性可以设置着色器输入和参数,还可以确定特定着色器是否需要输入或参数。 data 属性是一个 ShaderData 实例。 识别着色器输入和参数 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 指定着色器输入和参数值的第一步是确定要使用的特定着色器是否需要输入图像或参数。每个 Shader 实例都有一个包含 ShaderData 对象的 data 属性。如果着色器定义了任何输入或参数,则这些输入或参数可作为该 ShaderData 对象的属性进行 访问。属性的名称与在着色器源代码中为输入和参数指定的名称相匹配。例如,如果着色器定义了一个名为 src 的输入,则 ShaderData 对象具有一个名为 src 的属性用于表示该输入。每个表示输入的属性都是一个 ShaderInput 实例,而每个表示参 数的属性都是一个 ShaderParameter 实例。 理想情况下,着色器的创作者会提供着色器文档,用于指示着色器所需的输入图像值和参数、其所表示的内容以及正确的值等 等。 但是,如果着色器不带有文档 (并且您没有其源代码),则可以检查着色器数据以确定输入和参数。表示输入和参数的属性会 动态添加到 ShaderData 对象。因此,可以使用 for..in 循环检查 ShaderData 对象,以确定其关联着色器是否定义了输入或参 数。如第 254 页的 “ 访问着色器元数据 ” 中所述,为着色器定义的任何元数据值还可以作为添加到 Shader.data 属性的动态属 性进行访问。在使用这种方法识别着色器输入和参数时,请检查动态属性的数据类型。如果属性是 ShaderInput 实例,则表示 输入。如果是 ShaderParameter 实例,则表示参数。其他情况下,则是元数据值。下面的示例演示如何使用 for..in 循环检查 着色器的 data 属性的动态属性。每个输入 (ShaderInput 对象)都会添加到一个名为 inputs 的 Vector 实例。每个参数 (ShaderParameter 对象)都会添加到一个名为 parameters 的 Vector 实例。最后,所有元数据属性都会添加到一个名为 metadata 的 Vector 实例。请注意,此示例假设已创建了名为 myShader 的 Shader 实例: var shaderData:ShaderData = myShader.data; var inputs:Vector. = new Vector.(); var parameters:Vector. = new Vector.(); var metadata:Vector. = new Vector.(); for (var prop:String in shaderData) { if (shaderData[prop] is ShaderInput) { inputs[inputs.length] = shaderData[prop]; } else if (shaderData[prop] is ShaderParameter) { parameters[parameters.length] = shaderData[prop]; } else { metadata[metadata.length] = shaderData[prop]; } } // do something with the inputs or properties 指定着色器输入值 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 许多着色器需要一个或多个在着色器处理中使用的输入图像。但是,在很多情况下,输入是在使用 Shader 对象时自动指定的。 例如,假定着色器需要一个输入,并且该着色器用作滤镜。在滤镜应用于显示对象或 BitmapData 对象时,该对象会自动设置 为输入。在这种情况下,无需明确设置输入值。256ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 但是,在某些情况下,特别是在着色器定义多个输入时,一定要明确设置输入值。在 ActionScript 中,在着色器中定义的每 个输入都是由一个 ShaderInput 对象表示的。如第 255 页的 “ 识别着色器输入和参数 ” 中所述,ShaderInput 对象是 Shader 对象的 data 属性中的 ShaderData 实例的属性。例如,假定着色器定义一个名为 src 的输入,并且该着色器链接到一个名为 myShader 的 Shader 对象。在这种情况下,可使用下面的标识符访问对应于 src 输入的 ShaderInput 对象: myShader.data.src 每个 ShaderInput 对象都有一个 input 属性,该属性用于设置输入值。将 input 属性设置为 BitmapData 实例可指定图像数 据。此外,还可以将 input 属性设置为 BitmapData 或 Vector。 实例以指定二进制或数字数据。有关使用 BitmapData 或 Vector. 实例作为输入的详细信息和限制,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中的 ShaderInput.input 列表。 除了 input 属性之外,ShaderInput 对象还具有可用于确定输入所需图像类型的属性。这些属性包括 width、height 和 channels 属性。每个 ShaderInput 对象还有一个 index 属性,该属性用于确定是否必须为输入提供显式值。如果着色器需要的输入数量 大于自动设置的输入数量,则需要为这些输入设置值。有关使用着色器的不同方式,以及是否自动设置输入值的详细信息,请 参阅第 259 页的 “ 使用着色器 ”。 指定着色器参数值 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 某些着色器定义了参数值,着色器在创建其结果时会使用这些参数值。例如,更改图像亮度的着色器可能会指定一个亮度参 数,该参数确定操作影响亮度的程度。根据着色器中的参数定义,着色器中定义的单个参数可能需要单个值或多个值。在 ActionScript 中,在着色器中定义的每个参数都由一个 ShaderParameter 对象表示。如第 255 页的 “ 识别着色器输入和参数 ” 中所述,ShaderParameter 对象是 Shader 对象的 data 属性中的 ShaderData 实例的属性。例如,假定着色器定义一个名为 brightness 的参数,并且该着色器由一个名为 myShader 的 Shader 对象表示。在这种情况下,可使用下面的标识符访问对应于 brightness 参数的 ShaderParameter: myShader.data.brightness 若要为该参数设置一个 (或多个)值,请创建包含这个值 (或这些值)的 ActionScript 数组,并将该数组分配给 ShaderParameter 对象的 value 属性。 value 属性定义为 Array 实例,是因为单个着色器参数可能需要多个值。即使着色器参 数只需要一个值,也必须将该值包含在 Array 对象中才能将它分配给 ShaderParameter.value 属性。下面的代码演示如何将单个 值设置为 value 属性: myShader.data.brightness.value = [75]; 如果着色器的 Pixel Bender 源代码为参数定义默认值,则在创建 Shader 对象时,会创建包含默认值的数组,并将其分配给 ShaderParameter 对象的 value 属性。将数组分配给 value 属性之后 (包括该数组是默认数组的情况),可以通过更改数组元 素的值来更改参数值。您不需要创建新数组并将它分配给 value 属性。 下面的示例演示如何在 ActionScript 中设置着色器的参数值。在此示例中,着色器定义一个名为 color 的参数。在 Pixel Bender 源代码中,color 参数声明为 float4 变量,这意味着该参数是包含四个浮点数的数组。在该示例中,color 参数值会连续 更改,该参数每次更改时,都会使用着色器在屏幕上绘制一个有色的矩形。产生的结果是具有动画效果的颜色更改。 注: 此示例的代码由 Ryan Taylor 编写。感谢 Ryan 分享此示例。若要查看 Ryan 的个人资料并阅读他的文章,请访问 www.boostworthy.com/。 这段 ActionScript 代码以下面三个方法为中心: • init():在 init() 方法中,代码加载包含着色器的 Pixel Bender 字节代码文件。加载文件后,调用 onLoadComplete() 方法。 • onLoadComplete():在 onLoadComplete() 方法中,代码创建名为 shader 的 Shader 对象。同时还创建名为 texture 的 Sprite 实例。在 renderShader() 方法中,代码将着色器结果逐帧绘制在 texture 中。 • onEnterFrame():onEnterFrame() 方法按每帧一次的频率进行调用,用于创建动画效果。在此方法中,代码将着色器参数值 设置为新颜色,然后调用 renderShader() 方法将着色器结果绘制为矩形。257ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 • renderShader():在 renderShader() 方法中,代码调用 Graphics.beginShaderFill() 方法来指定着色器填充。然后,绘制一个 矩形,该矩形的填充由着色器输出 (生成的颜色)定义。有关以此方法使用着色器的详细信息,请参阅第 259 页的 “ 使用 着色器作为绘制填充 ”。 下面是此示例的 ActionScript 代码。使用此类作为 Flash Builder 中纯 ActionScript 项目的主应用程序类,或者作为 Flash Professional 中 FLA 文件的文档类: package { import flash.display.Shader; import flash.display.Sprite; import flash.events.Event; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; public class ColorFilterExample extends Sprite { private const DELTA_OFFSET:Number = Math.PI * 0.5; private var loader:URLLoader; private var shader:Shader; private var texture:Sprite; private var delta:Number = 0; public function ColorFilterExample() { init(); } private function init():void { loader = new URLLoader(); loader.dataFormat = URLLoaderDataFormat.BINARY; loader.addEventListener(Event.COMPLETE, onLoadComplete); loader.load(new URLRequest("ColorFilter.pbj")); } private function onLoadComplete(event:Event):void { shader = new Shader(loader.data); texture = new Sprite(); addChild(texture); addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(event:Event):void { 258ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 shader.data.color.value[0] = 0.5 + Math.cos(delta - DELTA_OFFSET) * 0.5; shader.data.color.value[1] = 0.5 + Math.cos(delta) * 0.5; shader.data.color.value[2] = 0.5 + Math.cos(delta + DELTA_OFFSET) * 0.5; // The alpha channel value (index 3) is set to 1 by the kernel's default // value. This value doesn't need to change. delta += 0.1; renderShader(); } private function renderShader():void { texture:graphics.clear(); texture.graphics.beginShaderFill(shader); texture.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight); texture.graphics.endFill(); } } } 下面是 ColorFilter 着色器内核的源代码,用于创建 “ColorFilter.pbj”Pixel Bender 字节代码文件: kernel ColorFilter < namespace : "boostworthy::Example"; vendor : "Ryan Taylor"; version : 1; description : "Creates an image where every pixel has the specified color value."; > { output pixel4 result; parameter float4 color < minValue:float4(0, 0, 0, 0); maxValue:float4(1, 1, 1, 1); defaultValue:float4(0, 0, 0, 1); >; void evaluatePixel() { result = color; } } 如果所使用的着色器的参数没有文档说明,则通过检查 ShaderParameter 对象的 type 属性,便可确定数组中必须包含的元素 数量及其类型。 type 属性指示着色器本身定义的参数数据类型。有关每种参数类型需要的元素数量和类型的列表,请参阅 “ActionScript 3.0 参考 ” 中的 ShaderParameter.value 属性列表。 每个 ShaderParameter 对象还有一个 index 属性,该属性指示参数在着色器参数顺序中的位置。除了这些属性之外, ShaderParameter 对象还可以具有包含由着色器创作者提供的元数据值的其他属性。例如,创作者可以指定元数据值,如参数 的最小值、最大值和默认值。创作者所指定的所有元数据值都会作为动态属性添加到 ShaderParameter 对象中。若要检查这 些属性,请使用 for..in 循环来循环访问 ShaderParameter 对象的动态属性,以识别其元数据。下面的示例演示如何使用 for..in 循环来识别 ShaderParameter 对象的元数据。每个元数据值都会添加到一个名为 metadata 的 Vector 实例。请注意,此示例 假定已创建了一个名为 myShader 的 Shader 实例,并且该实例具有一个名为 brightness 的参数:259ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 var brightness:ShaderParameter = myShader.data.brightness; var metadata:Vector. = new Vector.(); for (var prop:String in brightness) { if (brightness[prop] is String) { metadata[metadata.length] = brightness[prop]; } } // do something with the metadata 使用着色器 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 只要 Pixel Bender 着色器可以在 ActionScript 中用作 Shader 对象,就可以通过多种方式使用: • 着色器绘制填充:着色器定义使用绘图 API 绘制的形状的填充部分。 • 混合模式:着色器定义两个重叠的显示对象之间的混合。 • 滤镜:着色器定义用于修改可视内容外观的滤镜。 • 独立着色器处理:着色器处理在不指定输出的目标用途的情况下运行。着色器也可以在后台运行,结果在处理完成时可用。 这种方法可用于生成位图数据,还可用于处理非可视数据。 使用着色器作为绘制填充 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在使用着色器创建绘制填充时,您将使用绘图 API 方法来创建矢量形状。正如使用绘图 API 可将任何位图图像用作位图填充 一样,着色器的输出将用于填充该形状。若要创建着色器填充,可在代码中开始绘制形状的位置处,调用 Graphics 对象的 beginShaderFill() 方法。将 Shader 对象作为第一个参数传递给 beginShaderFill() 方法,如以下清单所示: var canvas:Sprite = new Sprite(); canvas.graphics.beginShaderFill(myShader); canvas.graphics.drawRect(10, 10, 150, 150); canvas.graphics.endFill(); // add canvas to the display list to see the result 在使用着色器作为绘制填充时,您将设置着色器需要的所有输入图像值和参数值。260ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 下面的示例演示如何使用着色器作为绘制填充。在此示例中,着色器创建了一个三点渐变。此渐变具有三种颜色,分别位于三 角形的三个顶点,之间的颜色为渐变混合。此外,颜色进行转动,产生旋转色的动画效果。 注: 此示例的代码由 Petri Leskinen 编写。感谢 Petri 分享此示例。若要查看 Petri 的更多示例和教程,请访问 http://pixelero.wordpress.com/。 这段 ActionScript 代码用到三个方法: • init():应用程序加载时调用 init() 方法。在此方法中,代码为代表三角形三个顶点的 Point 对象设置初始值。此外还创建名 为 canvas 的 Sprite 实例。稍后,在 updateShaderFill() 方法中,代码将着色器结果逐帧绘制在 canvas 中。最后,代码加载着 色器字节代码文件。 • onLoadComplete():在 onLoadComplete() 方法中,代码创建名为 shader 的 Shader 对象。此外还设置初始参数值。最后, 代码添加 updateShaderFill() 方法作为 enterFrame 事件的侦听器,表示逐帧调用该方法来创建动画效果。 • updateShaderFill():updateShaderFill() 方法是逐帧调用的,用于创建动画效果。在此方法中,代码计算并设置着色器的参数 值。然后,代码调用 beginShaderFill() 方法来创建着色器填充,调用其他绘图 API 方法在三角形中绘制着色器结果。 下面是此示例的 ActionScript 代码。使用此类作为 Flash Builder 中纯 ActionScript 项目的主应用程序类,或者作为 Flash Professional 中 FLA 文件的文档类: package { import flash.display.Shader; import flash.display.Sprite; import flash.events.Event; import flash.geom.Point; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; public class ThreePointGradient extends Sprite { private var canvas:Sprite; private var shader:Shader; private var loader:URLLoader; private var topMiddle:Point; private var bottomLeft:Point; private var bottomRight:Point; private var colorAngle:Number = 0.0; private const d120:Number = 120 / 180 * Math.PI; // 120 degrees in radians public function ThreePointGradient() 261ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 { init(); } private function init():void { canvas = new Sprite(); addChild(canvas); var size:int = 400; topMiddle = new Point(size / 2, 10); bottomLeft = new Point(0, size - 10); bottomRight = new Point(size, size - 10); loader = new URLLoader(); loader.dataFormat = URLLoaderDataFormat.BINARY; loader.addEventListener(Event.COMPLETE, onLoadComplete); loader.load(new URLRequest("ThreePointGradient.pbj")); } private function onLoadComplete(event:Event):void { shader = new Shader(loader.data); shader.data.point1.value = [topMiddle.x, topMiddle.y]; shader.data.point2.value = [bottomLeft.x, bottomLeft.y]; shader.data.point3.value = [bottomRight.x, bottomRight.y]; addEventListener(Event.ENTER_FRAME, updateShaderFill); } private function updateShaderFill(event:Event):void { colorAngle += .06; var c1:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle); var c2:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle + d120); var c3:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle - d120); shader.data.color1.value = [c1, c2, c3, 1.0]; shader.data.color2.value = [c3, c1, c2, 1.0]; shader.data.color3.value = [c2, c3, c1, 1.0]; canvas.graphics.clear(); canvas.graphics.beginShaderFill(shader); canvas.graphics.moveTo(topMiddle.x, topMiddle.y); canvas.graphics.lineTo(bottomLeft.x, bottomLeft.y); canvas.graphics.lineTo(bottomRight.x, bottomLeft.y); canvas.graphics.endFill(); } } } 下面是 ThreePointGradient 着色器内核的源代码,用于创建 “ThreePointGradient.pbj”Pixel Bender 字节代码文件:262ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 kernel ThreePointGradient < namespace : "Petri Leskinen::Example"; vendor : "Petri Leskinen"; version : 1; description : "Creates a gradient fill using three specified points and colors."; > { parameter float2 point1 // coordinates of the first point < minValue:float2(0, 0); maxValue:float2(4000, 4000); defaultValue:float2(0, 0); >; parameter float4 color1 // color at the first point, opaque red by default < defaultValue:float4(1.0, 0.0, 0.0, 1.0); >; parameter float2 point2 // coordinates of the second point < minValue:float2(0, 0); maxValue:float2(4000, 4000); defaultValue:float2(0, 500); >; parameter float4 color2 // color at the second point, opaque green by default < defaultValue:float4(0.0, 1.0, 0.0, 1.0); >; parameter float2 point3 // coordinates of the third point < minValue:float2(0, 0); maxValue:float2(4000, 4000); defaultValue:float2(0, 500); >; parameter float4 color3 // color at the third point, opaque blue by default < defaultValue:float4(0.0, 0.0, 1.0, 1.0); >; 263ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 output pixel4 dst; void evaluatePixel() { float2 d2 = point2 - point1; float2 d3 = point3 - point1; // transformation to a new coordinate system // transforms point 1 to origin, point2 to (1, 0), and point3 to (0, 1) float2x2 mtrx = float2x2(d3.y, -d2.y, -d3.x, d2.x) / (d2.x * d3.y - d3.x * d2.y); float2 pNew = mtrx * (outCoord() - point1); // repeat the edge colors on the outside pNew.xy = clamp(pNew.xy, 0.0, 1.0); // set the range to 0.0 ... 1.0 // interpolating the output color or alpha value dst = mix(mix(color1, color2, pNew.x), color3, pNew.y); } } 注: 如果在图形处理单元 (GPU) 下呈现时使用着色器填充,则填充区域将以蓝绿色着色。 有关使用绘图 API 绘制形状的详细信息,请参阅第 185 页的 “ 使用绘图 API”。 使用着色器作为混合模式 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 使用着色器作为混合模式与使用其他混合模式类似。着色器定义的外观取决于将两个显示对象混合在一起的视觉效果。若要将 着色器用于混合模式,请将 Shader 对象指派给前景显示对象的 blendShader 属性。如果为 blendShader 属性指定非 null 值,显 示对象的 blendMode 属性将自动设置为 BlendMode.SHADER。下面的清单演示如何使用着色器作为混合模式。注意,此示例 假定存在名为 foreground 的显示对象。该对象与其他显示内容包含在显示列表的同一父级中,而 foreground 与其他内容重叠: foreground.blendShader = myShader; 使用着色器作为混合模式时,着色器必须由至少两个输入定义。如示例所示,您未在代码中设置输入值。而是将两个混合后的 图像自动用作着色器的输入。前景图像设置为第二个图像。(此显示对象便是要对其应用混合模式的对象。)背景图像由前景图 像边框后的所有像素组合而成。背景图像设置为第一个输入图像。如果所用着色器要求两个以上的输入,则还需为前两个之外 的其他输入提供值。 下面的示例演示如何使用着色器作为混合模式。此示例使用基于亮度的加亮混合模式。混合的结果是以任一混合对象中最亮的 像素值显示该像素。 注: 此示例的代码由 Mario Klingemann 编写。感谢 Mario 分享此示例。若要查看 Mario 的更多作品及阅读他的文章,请访 问 www.quasimondo.com/。 这段重要的 ActionScript 代码用到下面两个方法: • init():应用程序加载时调用 init() 方法。在此方法中,代码加载着色器字节代码文件。 • onLoadComplete():在 onLoadComplete() 方法中,代码创建名为 shader 的 Shader 对象。然后绘制三个对象。第一个对象 backdrop 是混合对象后的深灰色背景。第二个对象 backgroundShape 是绿色渐变椭圆。第三个对象 foregroundShape 是橙色 渐变椭圆。264ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 foregroundShape 椭圆是混合的前景对象。混合的背景图像由部分 backdrop 和部分 backgroundShape 构成,并叠加了 foregroundShape 对象的边框。 foregroundShape 对象是位于显示列表最前面的对象。它与 backgroundShape 部分重叠,与 backdrop 全部重叠。由于上述重叠的存在,如果不应用混合模式,橙色椭圆 (foregroundShape) 将全部显示,并遮盖住绿色 椭圆 (backgroundShape) 的一部分: 而在应用混合模式之后,绿色椭圆的较亮部分会 “ 穿透 ” 前景显示出来,因为该部分比遮盖它的那部分 foregroundShape 更 亮。 下面是此示例的 ActionScript 代码。使用此类作为 Flash Builder 中纯 ActionScript 项目的主应用程序类,或者作为 Flash Professional 中 FLA 文件的文档类: package { import flash.display.BlendMode; import flash.display.GradientType; import flash.display.Graphics; import flash.display.Shader; import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.geom.Matrix; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; public class LumaLighten extends Sprite { private var shader:Shader; private var loader:URLLoader; public function LumaLighten() { init(); } private function init():void { loader = new URLLoader(); 265ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 loader.dataFormat = URLLoaderDataFormat.BINARY; loader.addEventListener(Event.COMPLETE, onLoadComplete); loader.load(new URLRequest("LumaLighten.pbj")); } private function onLoadComplete(event:Event):void { shader = new Shader(loader.data); var backdrop:Shape = new Shape(); var g0:Graphics = backdrop.graphics; g0.beginFill(0x303030); g0.drawRect(0, 0, 400, 200); g0.endFill(); addChild(backdrop); var backgroundShape:Shape = new Shape(); var g1:Graphics = backgroundShape.graphics; var c1:Array = [0x336600, 0x80ff00]; var a1:Array = [255, 255]; var r1:Array = [100, 255]; var m1:Matrix = new Matrix(); m1.createGradientBox(300, 200); g1.beginGradientFill(GradientType.LINEAR, c1, a1, r1, m1); g1.drawEllipse(0, 0, 300, 200); g1.endFill(); addChild(backgroundShape); var foregroundShape:Shape = new Shape(); var g2:Graphics = foregroundShape.graphics; var c2:Array = [0xff8000, 0x663300]; var a2:Array = [255, 255]; var r2:Array = [100, 255]; var m2:Matrix = new Matrix(); m2.createGradientBox(300, 200); g2.beginGradientFill(GradientType.LINEAR, c2, a2, r2, m2); g2.drawEllipse(100, 0, 300, 200); g2.endFill(); addChild(foregroundShape); foregroundShape.blendShader = shader; foregroundShape.blendMode = BlendMode.SHADER; } } } 下面是 LumaLighten 着色器内核的源代码,用于创建 “LumaLighten.pbj”Pixel Bender 字节代码文件:266ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 kernel LumaLighten < namespace : "com.quasimondo.blendModes"; vendor : "Quasimondo.com"; version : 1; description : "Luminance based lighten blend mode"; > { input image4 background; input image4 foreground; output pixel4 dst; const float3 LUMA = float3(0.212671, 0.715160, 0.072169); void evaluatePixel() { float4 a = sampleNearest(foreground, outCoord()); float4 b = sampleNearest(background, outCoord()); float luma_a = a.r * LUMA.r + a.g * LUMA.g + a.b * LUMA.b; float luma_b = b.r * LUMA.r + b.g * LUMA.g + b.b * LUMA.b; dst = luma_a > luma_b ? a : b; } } 有关使用混合模式的详细信息,请参阅第 154 页的 “ 应用混合模式 ”。 注: 当 Pixel Bender 着色器程序以混合模式在 Flash Player 或 AIR 中运行时,采样和 outCoord() 函数的行为与在其他上下文 中不同。在混合模式中,采样函数将始终返回着色器计算的当前像素。例如,您不能为了采集邻近像素而向 outCoord() 中添加 偏移。同样,如果您使用 outCoord() 函数而不使用采样函数,则其坐标的计算结果将始终为 0。例如,您无法利用像素的位置 来影响混合图像的合并方式。 使用着色器作为滤镜 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 使用着色器作为滤镜与在 ActionScript 中使用任何其他滤镜类似。使用着色器作为滤镜时,过滤出的图像 (显示对象或 BitmapData 对象)将传递给着色器。着色器使用输入图像来创建滤镜输出,该输出通常为原始图像经过修改的版本。如果过 滤出的对象是显示对象,着色器输出将显示在屏幕上,代替过滤出的显示对象。如果过滤出的对象是 BitmapData 对象,着色 器输出将成为 BitmapData 对象的内容,并调用该对象的 applyFilter() 方法。 若要使用着色器作为滤镜,您首先要创建 Shader 对象,如第 253 页的 “ 加载或嵌入着色器 ” 中所述。接下来,您需要创建链 接到该 Shader 对象的 ShaderFilter 对象。ShaderFilter 对象便是将应用到所过滤对象的滤镜。将滤镜应用于对象的方式与应 用任何滤镜的方式相同。将其传递给显示对象的 filters 属性,或者对 BitmapData 对象调用 applyFilter() 方法。例如,下面的 代码创建 ShaderFilter 对象,并将此滤镜应用到名为 homeButton 的显示对象。 var myFilter:ShaderFilter = new ShaderFilter(myShader); homeButton.filters = [myFilter]; 在使用着色器作为滤镜时,着色器必须由至少一个输入定义。如示例所示,您未在代码中设置输入值。而是将过滤出的显示对 象或 BitmapData 对象设置为输入图像。如果所用着色器要求一个以上的输入,则还需为第一个之外的其他输入提供值。 在某些情况下,滤镜会改变原始图像的尺寸。例如,典型的投影效果会添加额外的像素,这些像素组成为图像添加的阴影。在 使用更改图像尺寸的着色器时,需设置 leftExtension、rightExtension、topExtension 和 bottomExtension 属性,指明所需图像尺 寸更改量。267ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 下面的示例演示如何使用着色器作为滤镜。此示例中的滤镜将反转图像红绿蓝三色通道的值。其结果为该图像的 “ 负片 ” 版 本。 注: 此示例使用的着色器为 Pixel Bender 工具包中附带的 invertRGB.pbk Pixel Bender 内核。您可以从 Pixel Bender 工具 包安装目录中加载此内核的源代码。编译源代码,然后将字节代码文件保存到源代码所在的目录。 这段重要的 ActionScript 代码用到下面两个方法: • init():应用程序加载时调用 init() 方法。在此方法中,代码加载着色器字节代码文件。 • onLoadComplete():在 onLoadComplete() 方法中,代码创建名为 shader 的 Shader 对象。然后创建并绘制名为 target 的对 象的内容。 target 对象是用线性渐变色填充的矩形:左边是红色,中间是黄绿色,右边是淡蓝色。未过滤的对象看上去是这 样: 应用了滤镜后,颜色反转,矩形变成这样: 此示例使用的着色器为 Pixel Bender 工具包中附带的 “invertRGB.pbk”Pixel Bender 范例内核。源代码位于 Pixel Bender 工具包安装目录的 “invertRGB.pbk” 文件中。编译源代码,然后以文件名 “invertRGB.pbj” 将字节代码文件保存在 ActionScript 源代码所在的目录中。 下面是此示例的 ActionScript 代码。使用此类作为 Flash Builder 中纯 ActionScript 项目的主应用程序类,或者作为 Flash Professional 中 FLA 文件的文档类:268ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 package { import flash.display.GradientType; import flash.display.Graphics; import flash.display.Shader; import flash.display.Shape; import flash.display.Sprite; import flash.filters.ShaderFilter; import flash.events.Event; import flash.geom.Matrix; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; public class InvertRGB extends Sprite { private var shader:Shader; private var loader:URLLoader; public function InvertRGB() { init(); } private function init():void { loader = new URLLoader(); loader.dataFormat = URLLoaderDataFormat.BINARY; loader.addEventListener(Event.COMPLETE, onLoadComplete); loader.load(new URLRequest("invertRGB.pbj")); } private function onLoadComplete(event:Event):void { shader = new Shader(loader.data); var target:Shape = new Shape(); addChild(target); var g:Graphics = target.graphics; var c:Array = [0x990000, 0x445500, 0x007799]; var a:Array = [255, 255, 255]; var r:Array = [0, 127, 255]; var m:Matrix = new Matrix(); m.createGradientBox(w, h); g.beginGradientFill(GradientType.LINEAR, c, a, r, m); g.drawRect(10, 10, w, h); g.endFill(); var invertFilter:ShaderFilter = new ShaderFilter(shader); target.filters = [invertFilter]; } } } 有关应用滤镜的详细信息,请参阅第 224 页的 “ 创建和应用滤镜 ”。269ACTIONSCRIPT 3.0 开发人员指南 使用 Pixel Bender 着色器 上次更新 2014/12/1 在独立模式下使用着色器 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在独立模式下使用着色器时,着色器处理的运行独立于其输出结果的用途。指定要执行的着色器、设置输入值和参数值,及指 定用于放置结果数据的对象。在以下两种情形中,可以考虑以独立模式使用着色器: • 处理非图像数据:在独立模式下,您可以选择将任意二进制数据或数值数据 (而非位图图像数据)传递给着色器。除位图 图像数据外,您还可以选择将着色器结果以二进制数据或数值数据的形式返回。 • 背景处理:以独立模式运行着色器时,着色器默认为异步运行。这表示,在您的应用程序继续运行的同时,着色器以后台方 式运行,并在其处理结束时通知您的代码。您可以使用运行耗时的着色器,它在运行时不会导致应用程序用户界面或其他处 理响应迟缓。 使用 ShaderJob 对象以独立模式执行着色器。首先创建 ShaderJob 对象,并将其链接到代表要执行的着色器的 Shader 对象: var job:ShaderJob = new ShaderJob(myShader); 接下来,设置着色器需要的所有输入值或参数值。如果着色器在后台运行,还需要为 ShaderJob 对象的 complete 事件注册一 个侦听器。着色器完成其处理时,将调用该侦听器: function completeHandler(event:ShaderEvent):void { // do something with the shader result } job.addEventListener(ShaderEvent.COMPLETE, completeHandler); 接下来,创建着色器操作完成时,向其中写入操作结果的对象。将该对象指派给 ShaderJob 对象的 target 属性: var jobResult:BitmapData = new BitmapData(100, 75); job.target = jobResult; 如果使用 ShaderJob 执行图像处理,则为 target 属性指派一个 BitmapData 实例。如果要处理二进制数据或数值数据,则指派 ByteArray 对象或 Vector. 实例给 target 属性。在该情形下,您必须设置 ShaderJob 对象的 width 和 height 属性, 以指定输出到 target 对象的数据量。 注: 您可以一步完成 ShaderJob 对象 shader、target、width 和 height 属性的设置,方法是将相应的参数传递给 ShaderJob() 构 造函数,如:var job:ShaderJob = new ShaderJob(myShader, myTarget, myWidth, myHeight); 准备好执行着色器时,调用 ShaderJob 对象的 start() 方法: job.start(); 默认情况下,调用 start() 导致 ShaderJob 以异步方式执行。在这种情况下,程序立即继续执行下一行代码,而不等待着色器完 成处理。着色器操作完成时, ShaderJob 对象调用其 complete 事件的侦听器,通知它们操作已完成。在这里 (即 complete 事 件侦听器代码中), target 对象获得着色器操作结果。 注: 也可以不使用 target 属性对象,直接从传递给侦听器方法的事件对象处取得着色器结果。该事件对象是一个 ShaderEvent 实例。根据设置为 target 属性的对象的数据类型,ShaderEvent 对象有三个可用于访问结果的属性:ShaderEvent.bitmapData、 ShaderEvent.byteArray 和 ShaderEvent.vector。 或者,可以将 true 参数传递给 start() 方法。在该情形下,着色器操作将同步执行。所有代码 (包括与用户界面及所有其他事件 的交互)在着色器执行时暂停。着色器完成处理后, target 对象包含着色器结果,程序继续执行下一行代码。 job.start(true);270 上次更新 2014/12/1 第 16 章 : 使用影片剪辑 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 MovieClip 类是在 Adobe® Flash® 开发环境中创建的动画和影片剪辑元件的核心类。它具有显示对象的所有行为和功能,还具 有用于控制其时间轴的其他属性和方法。 影片剪辑基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 影片剪辑对于使用 Flash 创作工具创建动画内容并想要通过 ActionScript 来控制该内容的人来说是一个重要元素。只要在 Flash 中创建影片剪辑元件, Flash 就会将该元件添加到该 Flash 文档的库中。默认情况下,此元件会成为 MovieClip 类等具 有 MovieClip 类的属性和方法。 在将某个影片剪辑元件的实例放置在舞台上时,如果该影片剪辑具有多个帧,它会自动按其时间轴进行播放,除非使用 ActionScript 更改其播放。此时间轴使 MovieClip 类与其他类区别开来,允许您在 Flash 创作工具中通过补间动画或补间形 状来创建动画。相反,对于作为 Sprite 类的实例的显示对象,您只需以编程方式更改该对象的值即可创建动画。 在 ActionScript 的早期版本中, MovieClip 类是舞台上所有实例的基类。在 ActionScript 3.0 中,影片剪辑只是可以在屏幕 上显示的众多显示对象中的一个。如果使用显示对象时不需要时间轴,则使用 Shape 类或 Sprite 类替代 MovieClip 类可能会 提高呈示性能。有关为任务选择合适的显示对象的详细信息,请参阅第 143 页的 “ 选择 DisplayObject 子类 ”。 重要概念和术语 以下参考列表包含与影片剪辑相关的重要术语: AVM1 SWF 使用 ActionScript 1.0 或 ActionScript 2.0 创建的 SWF 文件,通常以 Flash Player 8 或更早期版本为目标播放 器。 AVM2 SWF 使用 Adobe Flash Player 9 或更高版本的 ActionScript 3.0 或者 Adobe AIR 创建的 SWF 文件。 外部 SWF 单独从项目 SWF 文件创建的 SWF 文件,将加载到项目 SWF 文件中并在该 SWF 文件中播放。 帧 时间轴上划分时间的最小单位。与运动图像电影胶片一样,每个帧都类似于动画在特定时间的快照,当快速按顺序播放各个 帧时,会产生动画的效果。 时间轴 组成影片剪辑动画序列的一系列帧的比喻性表示形式。 MovieClip 对象的时间轴等同于 Flash 创作工具中的时间轴。 播放头 一个标记,用于标识在给定时刻在时间轴中所处的位置 (帧)。 使用 MovieClip 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在发布 SWF 文件时, Flash 会将舞台上的所有影片剪辑元件实例转换为 MovieClip 对象。通过在属性检查器的 “ 实例名称 ” 字段中指定影片剪辑元件的实例名称,您可以在 ActionScript 中使用该元件。在创建 SWF 文件时, Flash 会生成在舞台上创 建该 MovieClip 实例的代码并使用该实例名称声明一个变量。如果您已经命名了嵌套在其他已命名影片剪辑内的影片剪辑,则 会将这些子级影片剪辑视为父级影片剪辑的属性,这样您便可以使用点语法访问该子影片剪辑。例如,如果实例名称为 childClip 的影片剪辑嵌套在实例名称为 parentClip 的另一个剪辑内,则可以通过调用以下代码来播放子剪辑的时间轴动画:271ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 parentClip.childClip.play(); 注: 在 Flash 创作工具中放到舞台上的子实例无法由父实例构造函数中的代码进行访问,因为在执行代码时尚未在该位置创建 这些实例。在访问子实例之前,父实例必须通过代码创建子实例,或者延迟访问用于侦听子实例以调度其 Event.ADDED_TO_STAGE 事件的回调函数。 尽管 ActionScript 2.0 MovieClip 类的一些旧方法和属性仍保持不变,但其他方法和属性已发生了变化。所有前缀为下划线的 属性均已被重新命名。例如,_width 和 _height 属性现在分别作为 width 和 height 被访问,而 _xscale 和 _yscale 则作为 scaleX 和 scaleY 被访问。有关 MovieClip 类的属性和方法的完整列表,请参考用于 Adobe Flash Platform 的 ActionScript 3.0 参 考。 控制影片剪辑播放 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Flash 利用时间轴来形象地表示动画或状态改变。任何使用时间轴的可视元素都必须为 MovieClip 对象或从 MovieClip 类扩 展而来。尽管 ActionScript 可控制任何影片剪辑的停止、播放或转至时间轴上的另一点,但不能用于动态创建时间轴或在特定 帧添加内容,这项工作仅能使用 Flash 创作工具来完成。 MovieClip 在播放时将以 SWF 文件的帧速率决定的速度沿着其时间轴推进。或者,您也可以通过在 ActionScript 中设置 Stage.frameRate 属性来覆盖此设置。 播放影片剪辑和停止播放 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 play() 和 stop() 方法允许对时间轴上的影片剪辑进行基本控制。例如,假设舞台上有一个影片剪辑元件,其中包含一个自行车 横穿屏幕的动画,其实例名称设置为 bicycle。如果将以下代码附加到主时间轴上的关键帧, bicycle.stop(); 自行车将不会移动 (将不播放其动画)。自行车的移动可以通过其他某种用户交互来开始。例如,如果您有一个名为 startButton 的按扭,则主时间轴上某一关键帧上的以下代码会使单击该按扭时播放该动画: // This function will be called when the button is clicked. It causes the // bicycle animation to play. function playAnimation(event:MouseEvent):void { bicycle.play(); } // Register the function as a listener with the button. startButton.addEventListener(MouseEvent.CLICK, playAnimation); 快进和后退 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在影片剪辑中,play() 和 stop() 方法并非是控制播放的唯一方法。也可以使用 nextFrame() 和 prevFrame() 方法手动向前或向后 沿时间轴移动播放头。调用这两种方法中的任一方法均会停止播放并分别使播放头向前或向后移动一帧。 使用 play() 方法类似于每次触发影片剪辑对象的 enterFrame 事件时调用 nextFrame()。使用此方法,您可以为 enterFrame 事件 创建一个事件侦听器并在侦听器函数中让 bicycle 回到前一帧,从而使 bicycle 影片剪辑向后播放,如下所示:272ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 // This function is called when the enterFrame event is triggered, meaning // it's called once per frame. function everyFrame(event:Event):void { if (bicycle.currentFrame == 1) { bicycle.gotoAndStop(bicycle.totalFrames); } else { bicycle.prevFrame(); } } bicycle.addEventListener(Event.ENTER_FRAME, everyFrame); 在正常播放过程中,如果影片剪辑包含多个帧,播放时将会无限循环播放,也就是说在经过最后一帧后将返回到第 1 帧。使用 prevFrame() 或 nextFrame() 时,不会自动发生此行为 (在播放头位于第 1 帧时调用 prevFrame() 不会将播放头移动到最后一 帧)。以上示例中的 if 条件将检查播放头是否已返回至第一帧,并将播放头设置为处于最后一帧前面,从而有效地使影片剪辑 向后持续循环播放。 跳到不同帧和使用帧标签 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 向新帧发送影片剪辑非常简单。调用 gotoAndPlay() 或 gotoAndStop() 将使影片剪辑跳到指定为参数的帧编号。或者,您可以传 递一个与帧标签名称匹配的字符串。可以为时间轴上的任何帧分配一个标签。为此,选择时间轴上的某一帧,然后在属性检查 器的 “ 帧标签 ” 字段中输入一个名称。 当创建复杂的影片剪辑时,使用帧标签比使用帧编号具有明显优势。当动画中的帧、图层和补间变得很多时,应考虑给重要的 帧加上具有解释性说明的标签来表示影片剪辑中的行为转换 (例如, “ 离开 ”、 “ 行走 ” 或 “ 跑 ”)。这可提高代码的可读性, 同时使代码更加灵活,因为转到添加了标签的帧的 ActionScript 调用是指向单个引用 (即 “ 标签 ”,而不是特定帧编号)的指 针。如果您以后决定将动画的特定片段移动到不同的帧,则无需更改 ActionScript 代码,只要将这些帧的相同标签保持在新位 置即可。 为便于在代码中表示帧标签, ActionScript 3.0 包括了 FrameLabel 类。此类的每个实例均代表一个帧标签,并具有一个 name 属性 (表示在属性检查器中指定的帧标签的名称)和一个 frame 属性 (表示该标签在时间轴上所处帧的帧编号)。 为了访问与影片剪辑实例相关联的 FrameLabel 实例, MovieClip 类包括了两个可直接返回 FrameLabel 对象的属性。 currentLabels 属性返回一个包含影片剪辑整个时间轴上所有 FrameLabel 对象的数组。 currentLabel 属性返回一个字符串,该 字符串包含在时间轴上最近遇到的帧标签的名称。 假设创建了一个名为 robot 的影片剪辑并已经为其动画的各个状态加上了标签。可以设置一个用于检查 currentLabel 属性的条 件以访问 robot 的当前状态,如下面的代码所示: if (robot.currentLabel == "walking") { // do something } Flash Player 11.3 和 AIR 3.3 向 FrameLabel 类中添加了 frameLabel 事件。您可以向表示帧标签的 FrameLabel 实例分配事 件处理函数。在播放头进入帧时调度事件。 下面的示例为 MovieClip 的帧标签数组中的第二个帧标签创建 FrameLabel 实例。然后它为 frameLabel 事件注册事件处理函 数:273ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 var myFrameLabel:FrameLabel = robot.currentLabels[1]; myFrameLabel.addEventListener(Event.FRAME_LABEL, onFrameLabel); function onFrameLabel(e:Event):void { //do something } 使用场景 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 Flash 创作环境中,您可以使用场景来区分 SWF 文件播放时将要经过的一系列时间轴。使用 gotoAndPlay() 或 gotoAndStop() 方法的第二个参数,可以指定要向其发送播放头的场景。所有 FLA 文件开始时都只有初始场景,但您可以创建 新的场景。 使用场景并非始终是最佳方法,因为场景有许多缺点。包含多个场景的 Flash 文档可能很难维护,尤其是在存在多个作者的环 境中。多个场景也会使带宽效率降低,因为发布过程会将所有场景合并为一个时间轴。这样将使所有场景进行渐进式下载,即 使从不会播放这些场景。因此,除非是组织冗长的基于多个时间轴的动画,否则通常不鼓励使用多个场景。 MovieClip 类的 scenes 属性返回表示 SWF 文件中所有场景的 Scene 对象的数组。currentScene 属性返回一个表示当前正在播 放的场景的 Scene 对象。 Scene 类具有多个提供有关场景信息的属性。labels 属性返回表示该场景中帧标签的 FrameLabel 对象的数组。name 属性以字 符串形式返回场景的名称。 numFrames 属性返回一个表示场景中帧的总数的整数。 使用 ActionScript 创建 MovieClip 对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 Flash 中向屏幕中添加内容的一个方法是将资源从库中拖放到舞台上,但不是仅有这一种方法。对于复杂项目,经验丰富的 开发人员通常更喜欢以编程方式创建影片剪辑。这种方法具有多个优点:代码更易于重用、编译时速度加快,以及仅可在 ActionScript 中进行的更复杂的修改。 ActionScript 3.0 的显示列表 API 简化了动态创建 MovieClip 对象的过程。直接实例化 MovieClip 实例的功能从向显示列表 中添加该实例的过程中分离出来,从而更加灵活、简单,而不会牺牲控制性能。 在 ActionScript 3.0 中,当以编程方式创建影片剪辑 (或任何其他显示对象)实例时,只有通过对显示对象容器调用 addChild() 或 addChildAt() 方法将该实例添加到显示列表中后,才能在屏幕上看到该实例。这允许您创建影片剪辑、设置其属 性,甚至可以在向屏幕呈示该影片剪辑之前调用方法。有关使用显示列表的详细信息,请参阅第 133 页的 “ 使用显示对象容器 ”。 为 ActionScript 导出库元件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 默认情况下, Flash 文档库中的影片剪辑元件实例不能以动态方式创建 (即只使用 ActionScript 创建)。这是因为导出供 ActionScript 使用的每个元件都会增加 SWF 文件的大小,而且众所周知,有些元件可能不适合在舞台上使用。因此,为了使 元件可以在 ActionScript 中使用,必须指定为 ActionScript 导出该元件。 为 ActionScript 导出元件: 1 在 “ 库 ” 面板中选择该元件并打开其 “ 元件属性 ” 对话框。 2 必要时激活 “ 高级 ” 设置。274ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 3 在 “ 链接 ” 部分中,激活 “ 为 ActionScript 导出 ” 复选框。 这将激活 “ 类 ” 和 “ 基类 ” 字段。 默认情况下,“ 类 ” 字段会用删除了空格的元件名称进行填充 (例如,名为 “Tree House” 的元件会变为 “TreeHouse”)。 若要指定该元件对其行为使用自定义类,请在此字段中输入该类的完整名称,包括它所在的包。如果希望在 ActionScript 中创建该元件的实例,但不需要添加任何其他行为,则可以使类名称保持原样。 “ 基类 ” 字段的值默认为 flash.display.MovieClip。如果想让元件扩展另一个自定义类的功能,可以指定该类的名称替代这个 值,只要该类扩展 Sprite (或 MovieClip)类即可。 4 按 “ 确定 ” 按钮以保存所做的更改。 此时,如果 Flash 无法找到链接的 SWC 文件,或包含指定类的定义的外部 ActionScript 文件 (例如,如果不需要为元件 添加其它行为),则会显示警告: 无法在类路径中找到对此类的定义,因此将在导出时自动在 SWF 文件中生成相应的定义。 如果库元件不需要超出 MovieClip 类功能的独特功能,则可以忽略此警告消息。 如果没有为元件提供类, Flash 将为元件创建一个等同于下面所示类的类: package { import flash.display.MovieClip; public class ExampleMovieClip extends MovieClip { public function ExampleMovieClip() { } } } 如果想要向元件中添加额外的 ActionScript 功能,请向下面的代码结构中添加相应的属性和方法。例如,假如有一个包含 50 像素宽和 50 像素高的圆形的影片剪辑元件,并用名为 Circle 的类指定为 ActionScript 导出该元件。以下代码在放入 Circle.as 文件后将扩展 MovieClip 类,同时为此元件提供额外的方法 getArea() 和 getCircumference(): package { import flash.display.MovieClip; public class Circle extends MovieClip { public function Circle() { } public function getArea():Number { // The formula is Pi times the radius squared. return Math.PI * Math.pow((width / 2), 2); } public function getCircumference():Number { // The formula is Pi times the diameter. return Math.PI * width; } } } 放置在 Flash 文档第 1 帧的关键帧上的以下代码将创建该元件的一个实例,并在屏幕上显示该实例:275ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 var c:Circle = new Circle(); addChild(c); trace(c.width); trace(c.height); trace(c.getArea()); trace(c.getCircumference()); 此代码演示了基于 ActionScript 的实例化可作为将单个资源拖放到舞台上的替代方法。它所创建的圆形具有影片剪辑的所有 属性,同时还具有 Circle 类中定义的自定义方法。这是一个非常简单的示例 — 您的库元件可在其类中指定任意数目的属性和 方法。 基于 ActionScript 的实例化功能强大,因为允许动态创建大量实例,而如果采用手动方式来创建将是一项繁重的任务。同时 还很灵活,因为您可以在创建每个实例时自定义该实例的属性。您可以通过使用循环动态创建多个 Circle 实例来体会上述优 点。在 Flash 文档库中存在上述 Circle 元件和类的情况下,将下面的代码放在第 1 帧的关键帧上: import flash.geom.ColorTransform; var totalCircles:uint = 10; var i:uint; for (i = 0; i < totalCircles; i++) { // Create a new Circle instance. var c:Circle = new Circle(); // Place the new Circle at an x coordinate that will space the circles // evenly across the Stage. c.x = (stage.stageWidth / totalCircles) * i; // Place the Circle instance at the vertical center of the Stage. c.y = stage.stageHeight / 2; // Change the Circle instance to a random color c.transform.colorTransform = getRandomColor(); // Add the Circle instance to the current timeline. addChild(c); } function getRandomColor():ColorTransform { // Generate random values for the red, green, and blue color channels. var red:Number = (Math.random() * 512) - 255; var green:Number = (Math.random() * 512) - 255; var blue:Number = (Math.random() * 512) - 255; // Create and return a ColorTransform object with the random colors. return new ColorTransform(1, 1, 1, 1, red, green, blue, 0); } 此代码演示了如何使用代码快速创建和自定义元件的多个实例。每个实例都根据循环内的当前计数进行定位,并且每个实例都 通过设置 transform 属性 (Circle 通过扩展 MovieClip 类而继承该属性)获得了一种随机颜色。 加载外部 SWF 文件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 ActionScript 3.0 中,SWF 文件是使用 Loader 类来加载的。若要加载外部 SWF 文件,ActionScript 需要执行以下 4 个 操作: 1 用文件的 URL 创建一个新的 URLRequest 对象。 2 创建一个新的 Loader 对象。276ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 3 调用 Loader 对象的 load() 方法,并以参数形式传递 URLRequest 实例。 4 对显示对象容器 (如 Flash 文档的主时间轴)调用 addChild() 方法,将 Loader 实例添加到显示列表中。 最后,代码如下所示: var request:URLRequest = new URLRequest("http://www.[yourdomain].com/externalSwf.swf"); var loader:Loader = new Loader() loader.load(request); addChild(loader); 通过指定图像文件的 URL 而不是 SWF 文件的 URL,可以使用上述同样的代码加载外部图像文件,如 JPEG、 GIF 或 PNG 图像。 SWF 文件不同于图像文件,可能包含 ActionScript。因此,虽然加载 SWF 文件的过程可能与加载图像的过程完全相 同,但如果 Flash Player 或 AIR 在播放 SWF,并且您计划使用 ActionScript 以某种方式与外部 SWF 文件通信,则在加载该 外部 SWF 文件时,执行加载的 SWF 文件和要加载的 SWF 文件必须位于同一个安全沙箱中。另外,如果外部 SWF 文件包含 了与执行加载的 SWF 文件中的类共享同一命名空间的类,可能需要为被加载的 SWF 文件创建新的应用程序域才能避免命名空 间冲突。有关安全性和应用程序域注意事项的详细信息,请参阅第 123 页的 “ 使用应用程序域 ” 和第 908 页的 “ 加载内容 ”。 当成功加载外部 SWF 文件后,可通过 Loader.content 属性访问该文件。如果该外部 SWF 文件是针对 ActionScript 3.0 发布 的,则加载的文件将为影片剪辑或 sprite,具体取决于所扩展的类。 与其他平台相比,在 Adobe AIR for iOS 中加载 SWF 文件存在一些不同之处。有关详细信息,请参阅第 167 页的 “ 在 AIR for iOS 中加载 SWF 文件 ”。 加载早期 SWF 文件的注意事项 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如果已使用早期版本的 ActionScript 发布了外部 SWF 文件,则需要考虑一些重要的限制条件。与在 AVM2 (ActionScript Virtual Machine 2) 中运行的 ActionScript 3.0 SWF 文件不同,针对 ActionScript 1.0 或 2.0 发布的 SWF 文件在 AVM1 (ActionScript Virtual Machine 1) 中运行。 将 ActionScript 1.0 或 2.0 SWF 文件加载到 ActionScript 3.0 SWF 文件时,(与加载 ActionScript 3.0 SWF 文件相比)有 重要区别。 Flash Player 提供与以前发布的内容的完全后向兼容性。在以前版本的 Flash Player 中运行的任何内容可在支持 ActionScript 3.0 的 Flash Player 版本中运行。但是,存在以下限制: • ActionScript 3.0 代码可以加载使用 ActionScript 1.0 或 2.0 编写的 SWF 文件。如果 ActionScript 1.0 或 2.0 SWF 文件 成功加载,加载的对象(Loader.content 属性)是 AVM1Movie 对象。AVM1Movie 实例不同于 MovieClip 实例。而是 显示对象,但不同于影片剪辑,它不包括与时间轴相关的方法或属性。父 AVM2 SWF 文件无法访问加载的 AVM1Movie 对象的属性、方法或对象。 • 以 ActionScript 1.0 或 2.0 编写的 SWF 文件无法加载以 ActionScript 3.0 编写的 SWF 文件。这意味着,在 Flash 8 或 Flex Builder 1.5 或更早版本中创作的 SWF 文件无法加载 ActionScript 3.0 SWF 文件。 此规则的唯一例外情况是,只要 ActionScript 2.0 SWF 文件以前没有向它的任何级别加载任何内容, ActionScript 2.0 SWF 文件就可以用 ActionScript 3.0 SWF 文件来替换它自身。ActionScript 2.0 SWF 文件可通过调用 loadMovieNum() 并将值 0 传递给 level 参数来实现此目的。 • 通常,如果使用 ActionScript 1.0 或 2.0 编写的 SWF 文件要与使用 ActionScript 3.0 编写的 SWF 文件一起使用,则必 须迁移前者。例如,假设您使用 ActionScript 2.0 创建了一个媒体播放器。此媒体播放器加载的也是使用 ActionScript 2.0 创建的多种内容。您无法使用 ActionScript 3.0 创建新内容并在此媒体播放器中加载新内容。您必须将视频播放器迁移到 ActionScript 3.0。 但是,如果您在 ActionScript 3.0 中创建一个媒体播放器,则该媒体播放器可以执行 ActionScript 2.0 内容的简单加载。 下面的表总结了以前版本的 Flash Player 在加载较新内容和执行代码方面的限制,以及在使用不同版本的 ActionScript 编写 的 SWF 文件之间进行跨脚本访问的限制。277ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 在下表中,“ 支持的功能 ” 指在 Flash Player 9 或更高版本中运行的内容。运行在 Flash Player 8 或更早版本中的内容只能在 ActionScript 1.0 和 2.0 中加载、显示、执行以及跨脚本编写。 影片剪辑示例:RuntimeAssetsExplorer Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 “ 为 ActionScript 导出 ” 功能非常适合用于在多个项目间使用库的情况。如果 Flash Player 或 AIR 执行 SWF 文件,则任何 SWF 文件只要与加载它的 SWF 处于同一安全沙箱中就可以使用已导出到 ActionScript 的元件。这样,单个 Flash 文档可生 成仅用于保存图形资源的 SWF 文件。此技术对大型项目特别有用,在这样的项目中,处理可视资源的设计人员可与创建 “ 包 装 ”SWF 文件的开发人员同时工作,然后在运行时加载图形资源 SWF 文件。您可以使用此方法维护一系列图形资源与编程开 发进度无关的版本文件。 RuntimeAssetsExplorer 应用程序加载属于 RuntimeAsset 子类的任何 SWF 文件,并允许您浏览该 SWF 文件的可用资源。 示例说明了以下过程: • 使用 Loader.load() 加载外部 SWF 文件 • 动态创建为 ActionScript 导出的库元件 • 使用 ActionScript 控制 MovieClip 播放 开始之前,注意每个要在 Flash Player 中运行的 SWF 文件必须位于同一个安全沙箱中。有关详细信息,请参阅第 895 页的 “ 安全沙箱 ”。 若要获取此范例的应用程序文件,请下载 Flash Professional 范例。 RuntimeAssetsExplorer 应用程序文件位于文件夹 Samples/RuntimeAssetsExplorer 中。该应用程序包含以下文件: 支持的功能 Flash Player 7 Flash Player 8 Flash Player 9 和 10 可以加载针对以下版本发布的 SWF 7 和更早版本 8 和更早版本 9 (或 10)及更低版本 包含此 AVM AVM1 AVM1 AVM1 和 AVM2 运行在以下 ActionScript 版本中编写的 SWF 1.0 和 2.0 1.0 和 2.0 1.0、 2.0 和 3.0 支持的功能 以 ActionScript 1.0 和 2.0 创建的内容 以 ActionScript 3.0 创建的内容 可以加载在以下版本中创建的内容并在其中执行 代码 仅 ActionScript 1.0 和 2.0 ActionScript 1.0、 2.0 和 ActionScript 3.0 可以对在以下版本中创建的内容进行跨脚本编写 仅 ActionScript 1.0 和 2.0 (通过本地连接的 ActionScript 3.0) ActionScript 1.0 和 2.0 (通过本地连接)。 ActionScript 3.0 文件 说明 RuntimeAssetsExample.mxml 或 RuntimeAssetsExample.fla 适用于 Flex (MXML) 或 Flash (FLA) 的应用程序的用户 界面。 RuntimeAssetsExample.as Flash (FLA) 应用程序的文档类。 GeometricAssets.as 用于实现 RuntimeAsset 接口的示例类。 GeometricAssets.fla 链接到 GeometricAssets 类的 FLA 文件 (该类是 FLA 的文档类)包含为 ActionScript 导出的元件。278ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 建立运行时库界面 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 若要使浏览器与 SWF 库正确交互,运行时资源库的结构就必须具有一定程式。我们将通过创建一个接口来完成此过程 (接口 类似于类,因为接口也是用于区分预期结构的方法的蓝图;同时接口又与类不同,因为接口不包含方法体)。接口提供了在运 行时库和浏览器之间相互通信的方法。加载到浏览器中的运行时资源的每个 SWF 都将实现此接口。有关接口及其使用方法的 更多信息,请参阅 《学习 ActionScript 3.0》中的 “ 接口 ”。 RuntimeLibrary 接口非常简单 — 我们只需要一个函数,这个函数能够为浏览器提供类路径的数组以导出元件并使元件在运行 时库中可用。为此,该接口具有单个方法:getAssets()。 package com.example.programmingas3.runtimeassetexplorer { public interface RuntimeLibrary { function getAssets():Array; } } 创建资源库 SWF 文件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 通过定义 RuntimeLibrary 接口,可以创建能够加载到另一个 SWF 文件中的多个资源库 SWF 文件。制作资源的单个 SWF 库包括四个任务: • 为资源库 SWF 文件创建一个类 • 为库中包含的单个资源创建类 • 创建实际图形资源 • 将图形元素与类关联并发布库 SWF 创建一个类以实现 RuntimeLibrary 接口 下一步,我们将创建要实现 RuntimeLibrary 接口的 GeometricAssets 类。这个类将成为 FLA 的文档类。此类的代码与 RuntimeLibrary 接口非常相似,不同之处在于,在类定义中, getAssets() 方法有方法体。 com/example/programmingas3/runtimeassetexplorer/RuntimeLibrary.as 用于定义将加载到浏览器容器中的所有运行时资源 SWF 文件所需方法的接口。 com/example/programmingas3/runtimeassetexplorer/AnimatingBox.as 形状为旋转方框的库元件的类。 com/example/programmingas3/runtimeassetexplorer/AnimatingStar.as 形状为旋转星形的库元件的类。 文件 说明279ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 package { import flash.display.Sprite; import com.example.programmingas3.runtimeassetexplorer.RuntimeLibrary; public class GeometricAssets extends Sprite implements RuntimeLibrary { public function GeometricAssets() { } public function getAssets():Array { return [ "com.example.programmingas3.runtimeassetexplorer.AnimatingBox", "com.example.programmingas3.runtimeassetexplorer.AnimatingStar" ]; } } } 如果要创建第二个运行时库,可以另外创建一个基于另一个类 (例如 AnimationAssets)的 FLA,该类可提供自带的 getAssets() 实现。 为每个 MovieClip 资源创建类 对于本示例,我们只扩展 MovieClip 类而不为自定义资源添加任何功能。以下 AnimatingStar 的代码类似于 AnimatingBox 的代码: package com.example.programmingas3.runtimeassetexplorer { import flash.display.MovieClip; public class AnimatingStar extends MovieClip { public function AnimatingStar() { } } } 发布库 现在将基于 MovieClip 的资源连接到新类,方法是创建一个新的 FLA 并在 “ 属性 ” 检查器的 “ 文档类 ” 字段中输入 GeometricAssets。为实现本示例的目的,我们将创建两个使用时间轴补间的非常简单的形状,其中一个形状顺时针旋转超过 360 帧。 animatingBox 和 animatingStar 元件都设为 “ 为 ActionScript 导出 ”,并将 “ 类 ” 字段设置为 getAssets() 实现中指定 的对应类路径。保留 flash.display.MovieClip 的默认基类,因为我们希望对标准 MovieClip 方法进行子分类。 在设置了元件的导出设置后,可发布 FLA。您现在便拥有了第一个运行时库。该 SWF 文件可以加载到另一个 AVM2 SWF 文 件中,且 AnimatingBox 和 AnimatingStar 元件可用于新的 SWF 文件。 将库加载到另一个 SWF 文件中 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 要处理的最后一个功能性部分是资源浏览器的用户界面。在本示例中,运行时库的路径硬编码为一个名为 ASSETS_PATH 的变 量。或者,您也可以使用 FileReference 类,例如,用来创建在硬盘驱动器上浏览特定 SWF 文件的接口。 成功加载运行时库后, Flash Player 会调用 runtimeAssetsLoadComplete() 方法:280ACTIONSCRIPT 3.0 开发人员指南 使用影片剪辑 上次更新 2014/12/1 private function runtimeAssetsLoadComplete(event:Event):void { var rl:* = event.target.content; var assetList:Array = rl.getAssets(); populateDropdown(assetList); stage.frameRate = 60; } 在此方法中,变量 rl 表示已加载的 SWF 文件。代码将调用已加载的 SWF 文件的 getAssets() 方法,获取可用资源的列表,并 通过调用 populateDropDown() 方法用这些资源填充具有可用资源列表的 ComboBox 组件。该方法会依次存储每个资源的完 整类路径。单击用户界面上的 “ 添加 ” 按扭即会触发 addAsset() 方法: private function addAsset():void { var className:String = assetNameCbo.selectedItem.data; var AssetClass:Class = getDefinitionByName(className) as Class; var mc:MovieClip = new AssetClass(); ... } 此方法获取 ComboBox 中当前所选资源的类路径 (assetNameCbo.selectedItem.data),并使用 getDefinitionByName() 函数(来 自 flash.utils 包)获取对该资源的类的实际引用,以创建该资源的新实例。281 上次更新 2014/12/1 第 17 章 : 使用补间动画 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 第 160 页的 “ 对象动画 ” 介绍如何在 ActionScript 中实现脚本动画。 我们在这里介绍另一种创建动画的技术:补间动画。使用此技术,您可以通过使用 Adobe® Flash® Professional 在文档中交互 设置动画来创建移动。然后您可以在运行时将该动画用于基于 ActionScript 的动态动画。 Flash Professional 将自动生成实现补间动画的 ActionScript,并使其具有可复制性和重复使用性。 若要创建补间动画,您必须拥有 Flash Professional 的许可证。 更多帮助主题 fl.motion 包 补间动画基础知识 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 补间动画提供了创建动画的简单方法。 补间动画以帧到帧的方式修改显示对象属性 (如位置或旋转)。在显示对象移动期间,补间动画还可以通过应用各种滤镜和其 他属性来更改显示对象的外观。使用 Flash Professional 交互创建补间动画,会生成补间动画的 ActionScript。在 Flash 中, 可使用 “ 将动画复制为 ActionScript 3.0 脚本 ” 命令复制创建补间动画的 ActionScript。随后您便可以在您自己的动态动画中 重复使用该 ActionScript,以便在运行时创建移动效果。 有关创建补间动画的信息,请参阅 《使用 Flash Professional》 中的 “ 补间动画 ” 一节。 重要概念和术语 以下是一个与此功能相关的重要术语: 补间动画 一种构造,它生成显示对象在不同时间不同状态下的中间帧;提供使第一个状态平滑过渡到第二个状态的外观。用于 在舞台上移动显示对象,并使显示对象随时间而增大、缩小、旋转、淡化或更改颜色。 在 Flash 中复制补间动画脚本 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 补间生成的中间帧可显示处于时间轴上两个不同帧中的不同状态下的显示对象。它创建的外观可使第一个帧中的图像平滑过渡 到第二个帧中的图像。在补间动画中,外观的更改通常涉及显示对象位置的更改,因而可创建移动效果。除了调整显示对象的 位置之外,补间动画还可以对显示对象进行旋转、倾斜、调整大小或应用滤镜。 在 Flash 中,通过沿时间轴在两个关键帧之间移动显示对象来创建补间动画。 Flash 可自动生成描述补间的 ActionScript 代 码,您可以复制这些代码并将其保存在文件中。有关创建补间动画的信息,请参阅 《使用 Flash Professional》 中的 “ 补间动 画 ” 一节。282ACTIONSCRIPT 3.0 开发人员指南 使用补间动画 上次更新 2014/12/1 您可以通过两种方式访问 Flash 中的 “ 将动画复制为 ActionScript 3.0 脚本 ” 命令。第一种方式是通过舞台上的补间上下文菜 单: 1 在舞台上选择补间动画。 2 右键单击 (Windows) 或按住 Control 单击 (Macintosh)。 3 选择 “ 将动画复制为 ActionScript 3.0 脚本 . . .” 第二种方式是直接从 Flash“ 编辑 ” 菜单选择该命令: 1 在舞台上选择补间动画。 2 选择 “ 编辑 ”>“ 时间轴 ”>“ 将动画复制为 ActionScript 3.0 脚本 ”。 在复制了脚本后,将脚本粘贴到文件中并保存。 在创建某个补间动画并复制和保存脚本后,您可以按原样重复使用该脚本,也可以在您自己的基于 ActionScript 的动态动画 中修改该脚本。 合并补间动画脚本 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 您从 Flash 复制的 ActionScript 代码中的标头会列出支持补间动画所需的所有模块。 283ACTIONSCRIPT 3.0 开发人员指南 使用补间动画 上次更新 2014/12/1 补间动画类 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 基本的补间动画类是 fl.motion 包中的 AnimatorFactory 类、MotionBase 类和 Motion 类。根据补间动画所操作的属性,您 可能还需要其他类。例如,如果补间动画对显示对象进行变形或旋转,则需要导入相应的 flash.geom 类。如果补间动画应用了 滤镜,则需导入 flash.filter 类。在 ActionScript 中,补间动画是 Motion 类的实例。Motion 类存储可应用于可视对象的关键 帧动画序列。动画数据包括位置、缩放、旋转、倾斜、颜色、滤镜和缓动。 下面的 ActionScript 的复制源是在 Flash 中创建的补间动画,用于对实例名称为 Symbol1_2 的显示对象进行动画处理。这段 代码为一个名为 __motion_Symbol1_2 的 MotionBase 对象声明了一个变量。 MotionBase 类是 Motion 类的父级。 var __motion_Symbol1_2:MotionBase; 随后脚本创建 Motion 对象: __motion_Symbol1_2 = new Motion(); Motion 对象名称 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 上例中,Flash 自动为 Motion 对象生成名称 __motion_Symbol1_2。它将前缀 __motion_ 附加到显示对象名称。因此,自动生 成的名称基于 Flash 中补间动画的目标对象的实例名称。 Motion 对象的 duration 属性指示补间动画中的总帧数: __motion_Symbol1_2.duration = 200; 默认情况下,如果复制的补间动画所属的显示对象实例还没有实例名称,则 Flash 会自动对该实例进行命名。 当您在自己的动画中重用 Flash 创建的 ActionScript 时,可以保留 Flash 自动为补间生成的名称,也可以替换为其他名称。如 果您更改了补间名称,请确保在整个脚本中都更改该名称。 或者,您可以在 Flash 中将您选择的名称分配给补间动画的目标对象。然后创建补间动画并复制脚本。无论您使用哪种命名方 式,都要确保您的 ActionScript 代码中的每个 Motion 对象都有唯一的名称。 描述动画 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 MotionBase 类的 addPropertyArray() 方法添加用于描述每个补间属性的值数组。 该数组可能包含用于补间动画中每个关键帧的数组项。通常,这些数组中的一些数组包含的项数少于补间动画中的关键帧总 数。当数组中的最后一个值对于剩下的帧没有更改时,会发生这种情况。 如果数组参数的长度大于 Motion 对象的 duration 属性,则 addPropertyArray() 会相应地调整 duration 属性的值。它不会为以 前添加的属性添加关键帧。会为动画的额外帧保持新添加的关键帧。 Motion 对象的 x 和 y 属性描述补间对象在动画运行时不断改变的位置。如果显示对象的位置发生更改,则这些坐标是在每个 关键帧中最可能发生更改的值。您可以使用 addPropertyArray() 方法添加其他动画属性。例如,如果调整补间对象的大小,可 以添加 scaleX 和 scaleY 值。如果倾斜补间对象,则添加 scewX 和 skewY 值。如果旋转补间对象,则添加 rotationConcat 属性。 使用 addPropertyArray() 方法可定义以下补间属性:284ACTIONSCRIPT 3.0 开发人员指南 使用补间动画 上次更新 2014/12/1 在自动生成的脚本中添加的属性取决于在 Flash 中分配给补间动画的属性。在自定义自己的脚本版本时,您可以添加、删除或 修改其中一些属性。 下面的代码向名为 __motion_Wheel 的补间动画的属性赋值。在此示例中,补间显示对象在补间动画中的全部 29 个帧中都不 更改位置,而是在当前位置上旋转。分配给 rotationConcat 数组的多个值对旋转进行了定义。此补间动画的其他属性值无变 化。 __motion_Wheel = new Motion(); __motion_Wheel.duration = 29; __motion_Wheel.addPropertyArray("x", [0]); __motion_Wheel.addPropertyArray("y", [0]); __motion_Wheel.addPropertyArray("scaleX", [1.00]); __motion_Wheel.addPropertyArray("scaleY", [1.00]); __motion_Wheel.addPropertyArray("skewX", [0]); __motion_Wheel.addPropertyArray("skewY", [0]); __motion_Wheel.addPropertyArray("rotationConcat", [ 0,-13.2143,-26.4285,-39.6428,-52.8571,-66.0714,-79.2857,-92.4999,-105.714, -118.929,-132.143,-145.357,-158.571,-171.786,-185,-198.214,-211.429,-224.643, -237.857,-251.071,-264.286,-277.5,-290.714,-303.929,-317.143,-330.357, -343.571,-356.786,-370 ] ); __motion_Wheel.addPropertyArray("blendMode", ["normal"]); 在下一个示例中,名为 Leaf_1 的显示对象会在舞台上移动。该对象的 x 和 y 属性数组为动画的 100 个帧中的每个帧包含不同的 值。此外,该对象在舞台上移动时同时在其 z 轴上旋转。 rotationZ 属性数组中的多个项确定了旋转方式。 x 对象的变形点在其父级的坐标空间中的水平位置 y 对象的变形点在其父级的坐标空间中的垂直位置 z 对象的变形点在其父级的坐标空间中的深度 (z 轴)位置 scaleX 从变形点开始应用的对象的水平缩放比例 (百分比) scaleY 从变形点开始应用的对象的垂直缩放比例 (百分比) skewX 从变形点开始应用的对象的水平倾斜角度 (以度为单位) skewY 从变形点开始应用的对象的垂直倾斜角度 (以度为单位) rotationX 对象相对于其原始方向围绕 x 轴的旋转 rotationY 对象相对于其原始方向围绕 y 轴的旋转 rotationConcat 动画中的对象的旋转 (z 轴)值,相对于前一个方向且从变形点开始应用 useRotationConcat 如果设置此属性,则会在 addPropertyArray() 提供动画数据时导致目标对象旋转 blendMode BlendMode 类值,指定对象的颜色与底层图形的混合 matrix3D matrix3D 属性 (如果对于关键帧存在此属性);用于 3D 补间;如果使用,则会忽略以前所有的变形属性 rotationZ 对象相对于 3D 父容器从其原始方向开始的 z 轴旋转 (以度为单位);用于 3D 补间 (而不是 rotationConcat)285ACTIONSCRIPT 3.0 开发人员指南 使用补间动画 上次更新 2014/12/1 __motion_Leaf_1 = new MotionBase(); __motion_Leaf_1.duration = 100; __motion_Symbol1_4.addPropertyArray("y", [ 0,5.91999,11.84,17.76,23.68,29.6,35.52,41.44,47.36,53.28,59.2,65.12,71.04, 76.96,82.88,88.8,94.72,100.64,106.56,112.48,118.4,124.32,130.24,136.16,142.08, 148,150.455,152.909,155.364,157.818,160.273,162.727,165.182,167.636,170.091, 172.545,175,177.455,179.909,182.364,184.818,187.273,189.727,192.182,194.636, 197.091,199.545,202,207.433,212.865,218.298,223.73,229.163,234.596,240.028, 245.461,250.893,256.326,261.759,267.191,272.624,278.057,283.489, 288.922,294.354,299.787,305.22,310.652,316.085,321.517,326.95,330.475,334, 337.525,341.05,344.575,348.1,351.625,355.15,358.675,362.2,365.725,369.25, 372.775,376.3,379.825,383.35,386.875,390.4,393.925,397.45,400.975,404.5, 407.5,410.5,413.5,416.5,419.5,422.5,425.5 ] ); __motion_Symbol1_4.addPropertyArray("scaleX", [1.00]); __motion_Symbol1_4.addPropertyArray("scaleY", [1.00]); __motion_Symbol1_4.addPropertyArray("skewX", [0]); __motion_Symbol1_4.addPropertyArray("skewY", [0]); __motion_Symbol1_4.addPropertyArray("z", [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ] ); __motion_Symbol1_4.addPropertyArray("rotationX", [64.0361]); __motion_Symbol1_4.addPropertyArray("rotationY", [41.9578]); __motion_Symbol1_4.addPropertyArray("rotationZ", [ -18.0336,-17.5536,-17.0736,-16.5936,-16.1136,-15.6336,-15.1536,-14.6736, -14.1936,-13.7136,-13.2336,-12.7536,-12.2736,-11.7936,-11.3136,-10.8336, -10.3536,-9.8736,-9.3936,-8.9136,-8.4336,-7.9536,-7.4736,-6.9936,-6.5136, -6.0336,-7.21542,-8.39723,-9.57905,-10.7609,-11.9427,-13.1245,-14.3063, -15.4881,-16.67,-17.8518,-19.0336,-20.2154,-21.3972,-22.5791,-23.7609, -24.9427,-26.1245,-27.3063,-28.4881,-29.67,-30.8518,-32.0336,-31.0771, -30.1206,-29.164,-28.2075,-27.251,-26.2945,-25.338,-24.3814,-23.4249, -22.4684,-21.5119,-20.5553,-19.5988,-18.6423,-17.6858,-16.7293,-15.7727 -14.8162,-13.8597,-12.9032,-11.9466,-10.9901,-10.0336,-10.9427,-11.8518, -12.7609,-13.67,-14.5791,-15.4881,-16.3972,-17.3063,-18.2154,-19.1245, -20.0336,-20.9427,-21.8518,-22.7609,-23.67,-24.5791,-25.4881,-26.3972, -27.3063,-28.2154,-29.1245,-30.0336,-28.3193,-26.605,-24.8907,-23.1765, -21.4622,-19.7479,-18.0336 ] ); __motion_Symbol1_4.addPropertyArray("blendMode", ["normal"]); 添加滤镜 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 如果补间动画的目标对象包含滤镜,则这些滤镜是使用 Motion 类的 initFilters() 和 addFilterPropertyArray() 方法添加的。 286ACTIONSCRIPT 3.0 开发人员指南 使用补间动画 上次更新 2014/12/1 初始化滤镜数组 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 initFilters() 方法将初始化滤镜。该方法的第一个参数是应用于显示对象的所有滤镜的完全限定类名称的数组。此滤镜名称数组 是从 Flash 中的补间动画滤镜列表生成的。在您的脚本副本中,您可以在此数组中删除或添加 flash.filters 包中的任何滤镜。下 面的调用初始化目标显示对象的滤镜列表。该调用应用 DropShadowFilter、GlowFilter 和 BevelFilter,并将列表复制到 Motion 对象中的每个关键帧。 __motion_Box.initFilters(["flash.filters.DropShadowFilter", "flash.filters.GlowFilter", "flash.filters.BevelFilter"], [0, 0, 0]); 添加滤镜 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 addFilterPropertyArray() 方法使用以下参数描述已初始化滤镜的属性: 1 该方法的第一个参数通过索引标识滤镜。该索引指示滤镜名称在滤镜类名称数组中的位置,该数组是在前一个 initFilters() 调用中传递的。 2 该方法的第二个参数是在每个关键帧中为该滤镜存储的滤镜属性。 3 该方法的第三个参数是指定滤镜属性的值。 在进行了前一个 initFilters() 调用后,随后的 addFilterPropertyArray() 调用将值 5 分配给 DropShadowFilter 的 blurX 和 blurY 属 性。 DropShadowFilter 是已初始化的滤镜数组中的第一个 (索引为 0)项: __motion_Box.addFilterPropertyArray(0, "blurX", [5]); __motion_Box.addFilterPropertyArray(0, "blurY", [5]); 接下来的三个调用向已初始化滤镜数组中的第二个项 (索引为 1) GlowFilter 的 quality、 alpha 和 color 属性赋值。 __motion_Box.addFilterPropertyArray(1, "quality", [BitmapFilterQuality.LOW]); __motion_Box.addFilterPropertyArray(1, "alpha", [1.00]); __motion_Box.addFilterPropertyArray(1, "color", [0xff0000]); 接下来的四个调用向已初始化滤镜数组的第三个项(索引为 2)BevelFilter 的 shadowAlpha、shadowColor、highlightAlpha 和 highlightColor 赋值。 __motion_Box.addFilterPropertyArray(2, "shadowAlpha", [1.00]); __motion_Box.addFilterPropertyArray(2, "shadowColor", [0x000000]); __motion_Box.addFilterPropertyArray(2, "highlightAlpha", [1.00]); __motion_Box.addFilterPropertyArray(2, "highlightColor", [0xffffff]); 使用 ColorMatrixFilter 调整颜色 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 在初始化 ColorMatrixFilter 之后,您可以设置相应的 AdjustColor 属性来调整补间显示对象的亮度、对比度、饱和度和色相。 通常,在 Flash 中创建补间动画时,会应用 AdjustColor 滤镜;您可以在 ActionScript 的副本中对其进行微调。下面的示例在 显示对象移动期间转换该对象的色相和饱和度。287ACTIONSCRIPT 3.0 开发人员指南 使用补间动画 上次更新 2014/12/1 __motion_Leaf_1.initFilters(["flash.filters.ColorMatrix"], [0], -1, -1); __motion_Leaf_1.addFilterPropertyArray(0, "adjustColorBrightness", [0], -1, -1); __motion_Leaf_1.addFilterPropertyArray(0, "adjustColorContrast", [0], -1, -1); __motion_Leaf_1.addFilterPropertyArray(0, "adjustColorSaturation", [ 0,-0.589039,1.17808,-1.76712,-2.35616,-2.9452,-3.53424,-4.12328, -4.71232,-5.30136,-5.89041, 6.47945,-7.06849,-7.65753,-8.24657, -8.83561,-9.42465,-10.0137,-10.6027,-11.1918,11.7808,-12.3699, -12.9589,-13.5479,-14.137,-14.726,-15.3151,-15.9041,-16.4931, 17.0822,-17.6712,-18.2603,-18.8493,-19.4383,-20.0274,-20.6164, -21.2055,-21.7945,22.3836,-22.9726,-23.5616,-24.1507,-24.7397, -25.3288,-25.9178,-26.5068,-27.0959,27.6849,-28.274,-28.863,-29.452, -30.0411,-30.6301,-31.2192,-31.8082,-32.3973,32.9863,-33.5753, -34.1644,-34.7534,-35.3425,-35.9315,-36.5205,-37.1096,-37.6986, 38.2877,-38.8767,-39.4657,-40.0548,-40.6438,-41.2329,-41.8219, -42.411,-43 ], -1, -1); __motion_Leaf_1.addFilterPropertyArray(0, "adjustColorHue", [ 0,0.677418,1.35484,2.03226,2.70967,3.38709,4.06451,4.74193,5.41935, 6.09677,6.77419,7.45161,8.12903,8.80645,9.48387,10.1613,10.8387,11.5161, 12.1935,12.871,13.5484,14.2258,14.9032,15.5806,16.2581,16.9355,17.6129, 18.2903,18.9677,19.6452,20.3226,21,22.4286,23.8571,25.2857,26.7143,28.1429, 29.5714,31,32.4286,33.8571,35.2857,36.7143,38.1429,39.5714,41,42.4286,43.8571, 45.2857,46.7143,48.1429,49.5714,51,54,57,60,63,66,69,72,75,78,81,84,87, 90,93,96,99,102,105,108,111,114 ], -1, -1); 将补间动画与其显示对象关联 Flash Player 9 及更高版本, Adobe AIR 1.0 及更高版本,需要 Flash CS3 或更高版本 最后一项任务是将补间动画与它所操作的一个或多个显示对象关联起来。 AnimatorFactory 类管理补间动画与其目标显示对象之间的关联。 AnimatorFactory 构造函数的参数为 Motion 对象: var __animFactory_Wheel:AnimatorFactory = new AnimatorFactory(__motion_Wheel); 使用 AnimatorFactory 类的 addTarget() 方法可将目标显示对象与其补间动画关联起来。从 Flash 复制的 ActionScript 注释 掉了 addTarget() 代码行,并且未指定实例名称: // __animFactory_Wheel.addTarget(, 0); 在您的副本中,指定要与补间动画关联的显示对象。在下面的示例中,目标指定为 greenWheel 和 redWheel: __animFactory_Wheel.AnimatorFactory.addTarget(greenWheel, 0); __animFactory_Wheel.AnimationFactory.addTarget(redWheel, 0); 您可以使用多个 addTarget() 调用,将多个显示对象与同一个补间动画关联起来。288 上次更新 2014/12/1 第 18 章 : 使用反向运动 Flash Player 10 及更高版本, Adobe AIR 1.5 及更高版本,需要 Flash CS4 或更高版本 反向运动 (IK) 是一种用于创建逼真运动的重要方法。 使用 IK 可以在一系列连接的部分 (称为 IK 骨架)中创建协调运动,以便各部分以逼真的方式一起移动。骨架的各部分是其 骨骼和连接。如果给定骨架的终点, IK 便可计算出达到该终点所需的连接的角度。 自己手动计算这些角度难度很大。此功能的优点在于您可以使用 Adobe® Flash® Professional 以交互方式创建骨架。然后可以 使用 ActionScript 对骨架进行动画处理。 Flash Professional 中附带的 IK 引擎可进行计算,以描述骨架的移动。您可以在 ActionScript 代码中使用某些参数限制移动。 此 Flash Professional CS5 版本的 IK 新增了骨骼弹簧概念,通常与高端动画应用程序相关联。与新增动态物理引擎配合使 用,此功能可将动作配置得栩栩如生。并且,无论在运行时还是创作期间都可达到这种效果。 若要创建反向运动骨架,您必须拥有 Flash Professional 的许可证。 更多帮助主题 fl.ik 包 反向运动的基础知识 Flash Player 10 及更高版本, Adobe AIR 1.5 及更高版本,需要 Flash CS4 或更高版本 使用反向运动 (IK) 可以将不同的部分链接起来,使它们以逼真的方式进行相对移动,从而创建逼真的动画效果。 例如,使用 IK 时,您可以根据需要移动某条腿的连接将那条腿移动到特定的位置,从而获得所需的姿势。 IK 使用一种骨骼框 架,这些骨骼采用称为 “IK 骨架 ” 的结构连接在一起。 fl.ik 包可帮助您创建模仿自然运动的动画。使用该包可以对多个 IK 骨架 进行无缝动画处理,而不必了解很多 IK 算法所依赖的物理知识。 使用 Flash Professional 创建 IK 骨架及其辅助骨骼和连接。然后您便可以在运行时访问 IK 类以对它们进行动画处理。 有关如何创建 IK 骨架的详细介绍,请参阅 《使用 Flash Professional》中的 “ 使用反向运动 ” 一节。 重要概念和术语 以下参考列表中包含与此功能相关的重要术语: 骨架 一种由骨骼和联结点组成的运动链,用于在计算机动画中模拟真实运动。 骨骼 骨架中的刚性段,类似于动物骨架中的骨骼。 反向运动 (IK) 确定连接的灵活对象 (称为运动链或骨架)的参数的过程。 联结点 两块骨骼接合的位置,构建在一起从而使骨骼可以移动;类似于动物的关节。 物理引擎 与物理相关联的算法包,用于为动画提供逼真的动作。 弹簧 当父骨骼移动时移动并响应、并随时间变化以增量方式下降的骨骼质量。289ACTIONSCRIPT 3.0 开发人员指南 使用反向运动 上次更新 2014/12/1 IK 骨架动画处理概述 Flash Player 10 及更高版本, Adobe AIR 1.5 及更高版本,需要 Flash CS4 或更高版本 在 Flash Professional 中创建 IK 骨架后,可使用 fl.ik 类在运行时限制骨架的移动、跟踪其事件并对其进行动画处理。 下图演示了一个名为 Wheel 的影片剪辑。 轴是一个名为 Axle 的 IKArmature 实例。IKMover 类会在轮子旋转时同步移动骨架。 骨架中的 IKBone (ikBone2) 在其尾部连接处附加到轮子。 A. Wheel B. Axle C. ikBone2 在运行时,轮子结合 __motion_Wheel 补间动画 (在第 283 页的 “ 描述动画 ” 中进行了介绍)进行旋转。由一个 IKMover 对 象启动和控制轴的移动。下图演示了附加到旋转轮上的轴骨架在旋转中的不同帧上的两个快照。 在运行时,下面的 ActionScript 可完成以下功能: • 获取有关骨架及其组件的信息 • 实例化 IKMover 对象 • 结合轮子的旋转移动轴 B A C290ACTIONSCRIPT 3.0 开发人员指南 使用反向运动 上次更新 2014/12/1 import fl.ik.* var tree:IKArmature = IKManager.getArmatureByName("Axle"); var bone:IKBone = tree.getBoneByName("ikBone2"); var endEffector:IKJoint = bone.tailJoint; var pos:Point = endEffector.position; var ik:IKMover = new IKMover(endEffector, pos); ik.limitByDistance = true; ik.distanceLimit = 0.1; ik.limitByIteration = true; ik.iterationLimit = 10; Wheel.addEventListener(Event.ENTER_FRAME, frameFunc); function frameFunc(event:Event) { if (Wheel != null) { var mat:Matrix = Wheel.transform.matrix; var pt = new Point(90, 0); pt = mat.transformPoint(pt); ik.moveTo(pt); } } 用于移动轴的 IK 类为: • IKArmature:描述骨架 (由骨骼和连接组成的树结构);必须使用 Flash 创建 Professional • IKManager:文档中所有 IK 骨架的容器类;必须使用 Flash Professional 创建 • IKBone:IK 骨架的一段 • IKJoint:两个 IK 骨骼之间的连接 • IKMover:启动和控制骨架的 IK 移动 有关这些类的完整和详细描述,请参阅 ik 包。 获取有关 IK 骨架的信息 Flash Player 10 及更高版本, Adobe AIR 1.5 及更高版本,需要 Flash CS4 或更高版本 首先,为组成要移动的各部分的骨架、骨骼和连接声明变量。 下面的代码使用 IKManager 类的 getArmatureByName() 方法将 Axle 骨架的值分配给 IKArmature 变量 tree。Axle 骨架是先 前使用 Flash Professional 创建的。 var tree:IKArmature = IKManager.getArmatureByName("Axle"); 同样,下面的代码使用 IKArmature 类的 getBoneByName() 方法将 ikBone2 骨骼的值分配给 IKBone 变量。 var bone:IKBone = tree.getBoneByName("ikBone2"); ikBone2 骨骼的尾部连接是附加到旋转轮的骨架部分。 下行代码声明变量 endEffector 并将 ikBone2 骨骼的 tailjoint 属性分配给该变量: var endEffector:IKJoint = home.tailjoint; 变量 pos 是用于存储 endEffector 连接的当前位置的点。291ACTIONSCRIPT 3.0 开发人员指南 使用反向运动 上次更新 2014/12/1 var pos:Point = endEffector.position; 在此示例中, pos 是处于轴尾部 (轴在此处与轮子连接)的连接的位置。此变量的原始值是通过 IKJoint 的 position 属性获取 的。 实例化 IKMover 并限制其移动 Flash Player 10 及更高版本, Adobe AIR 1.5 及更高版本,需要 Flash CS4 或更高版本 由 IKMover 类的实例移动轴。 下行代码实例化 IKMover 对象 ik,将要移动的元素和移动的起始点传递给该对象的构造函数: var ik:IKMover = new IKMover(endEffector, pos); 使用 IKMover 类的属性可以限制骨架的移动。可以基于移动的距离、迭代和时间来限制移动。 以下几对属性可强制执行这些限制。这几对属性包括一个用于指示是否限制移动的布尔值和一个用于指定限制量的整数: 默认情况下,所有布尔值都设置为 false,因此除非您明确地将布尔值设置为 true,否则移动不会受限制。若要强制执行限制, 可将适当的属性设置为 true,然后为相应的整数属性指定一个值。如果您将限制设置为某个值,却没有设置其对应的 Boolean 属性,则会忽略该限制。在这种情况下, IK 引擎继续移动对象,直至达到其他限制或 IKMover 的目标位置。 在下面的示例中,骨架移动的最大距离设置为每次迭代 0.1 个像素。每个移动的最大迭代次数设置为 10。 ik.limitByDistance = true; ik.distanceLimit = 0.1; ik.limitByIteration = true; ik.iterationLimit = 10; 移动 IK 骨架 Flash Player 10 及更高版本, Adobe AIR 1.5 及更高版本,需要 Flash CS4 或更高版本 IKMover 可在轮子的事件侦听器中移动轴。在轮子的每个 enterFrame 事件中,都会计算骨架的新目标位置。IKMover 使用 其 moveTo() 方法将尾部连接移动到其目标位置,或是在通过其 limitByDistance、limitByIteration 和 limitByTime 属性设置的限 制下移动到尽可能远的位置。 布尔属性 整数属性 限制设置 limitByDistance:Boolean distanceLimit:int 设置 IK 引擎对每次迭代移动的最大距离 (以像素为单位)。 limitByIteration:Boolean iterationLimit:int 设置 IK 引擎对每个移动执行的最大迭代次数。 limitByTime:Boolean timeLimit:int 设置分配给 IK 引擎用于执行移动的最长时间 (以毫秒为单位)。292ACTIONSCRIPT 3.0 开发人员指南 使用反向运动 上次更新 2014/12/1 Wheel.addEventListener(Event.ENTER_FRAME, frameFunc); function frameFunc(event:Event) { if (Wheel != null) { var mat:Matrix = Wheel.transform.matrix; var pt = new Point(90,0); pt = mat.transformPoint(pt); ik.moveTo(pt); } } 使用弹簧 Flash Player 10 及更高版本, Adobe AIR 1.5 及更高版本,需要 Flash CS5 或更高版本 Flash Professional CS5 中的反向运动支持骨骼弹簧。可在创作期间设置骨骼弹簧,并且可在运行时添加或修改骨骼弹簧属 性。弹簧是骨骼及其关节的属性。它包含两个属性:一个是 IKJoint.springStrength,用于设置弹簧的量;另一个是 IKJoint.springDamping,用于将向强度值添加阻力并更改弹簧的衰减率。 弹簧强度是介于 0-100 的百分比值, 0 表示完全刚性 (默认值), 100 表示很松散且由物理特性控制。具有弹簧的骨骼响应其 关节的移动。如果未启用其他转换 (旋转、 x 或 y),弹簧设置无效。 弹簧阻尼是介于 0-100 的百分比值, 0 表示没有阻力 (默认值), 100 表示强阻尼的。阻尼会影响从骨骼初始移动到返回静止 状态所用的时间。 要了解 IKArmature 对象是否启用了弹簧,请查看对象的 IKArmature.springsEnabled 属性。其他弹簧属性和方法属于各个 IKJoint 对象。可以为关节启用角度旋转和沿 X 轴和 Y 轴的平移。您可使用 IKJoint.setSpringAngle 指定旋转关节的弹簧角度位 置,使用 IKJoint.setSpringPt 指定平移关节的弹簧位置。 在以下示例中,通过名称选择了骨骼并标识了其尾关节。代码测试父骨架,以查看是否已启用弹簧,然后为关节设置弹簧属 性。 var arm:IKArmature = IKManager.getArmatureAt(0); var bone:IKBone = arm.getBoneByName("c"); var joint:IKJoint = bone.tailJoint; if (arm.springsEnabled) { joint.springStrength = 50; //medium spring strength joint.springDamping = 10; //light damping resistance if (joint.hasSpringAngle) { joint.setSpringAngle(30); //set angle for rotational spring } } 使用 IK 事件 Flash Player 10 及更高版本, Adobe AIR 1.5 及更高版本,需要 Flash CS4 或更高版本 使用 IKEvent 类可以创建包含有关 IK 事件的信息的事件对象。IKEvent 信息描述由于超过指定时间、距离或迭代限制而终止 的运动。 下面的代码演示用于跟踪时间限制事件的一个事件侦听器和处理函数。此事件处理函数在超过 IKMover 的时间限制时,报告 所引发的事件的时间、距离、迭代计数和连接属性。293ACTIONSCRIPT 3.0 开发人员指南 使用反向运动 上次更新 2014/12/1 var ikmover:IKMover = new IKMover(endjoint, pos); ikMover.limitByTime = true; ikMover.timeLimit = 1000; ikmover.addEventListener(IKEvent.TIME_LIMIT, timeLimitFunction); function timeLimitFunction(evt:IKEvent):void { trace("timeLimit hit"); trace("time is " + evt.time); trace("distance is " + evt.distance); trace("iterationCount is " + evt.iterationCount); trace("IKJoint is " + evt.joint.name); }294 上次更新 2014/12/1 第 19 章 : 在三维 (3D) 环境中工作 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 Flash Player 和 AIR 运行时可通过两种方式支持 3D 图形。您可以使用 Flash 显示列表上的三维显示对象。此方法适用于为 Flash 内容添加三维效果以及适用于多边形数量很少的对象。在 Flash Player 11 和 AIR 3 或更高版本中,可以使用 Stage3D API 呈现复杂 3D 场景。 Stage3D 视口不是显示对象。相反, 3D 图形会呈现于显示在 Flash 显示列表下方 (并且在任何 StageVideo 视口平面上方) 的视口中。您可以使用可编程的 3D 管道(与 OpenGL 和 Direct3D 类似)替代 Flash DisplayObject 类来创建场景。此管道 将三角形数据和纹理作为输入并使用提供的着色器程序来渲染场景。如果客户端计算机上存在兼容的图形处理单元 (GPU) 并 具有受支持的驱动程序,则将使用硬件加速。 Stage3D 提供最底层的 API。在应用程序中,我们鼓励您使用支持 Stage3D 的 3D 框架。您可以创建自已的框架,或者使用 已经提供的几个商业和开放源框架之一。 有关使用 Stage3D 开发 3D 应用程序以及可用 3D 框架的详细信息,请访问 Flash Player 开发人员中心:Stage 3D。 3D 显示对象的基础知识 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 二维 (2D) 对象和投影在二维屏幕上的三维 (3D) 对象之间的区别在于,三维对象增加了第三维。第三维使对象能够靠近或远离 用户的视点。 如果将某个显示对象的 z 属性明确设置为数值,则该对象会自动创建一个 3D 转换矩阵。您可以通过更改此矩阵来修改该对象 的 3D 转换设置。 此外, 3D 旋转与 2D 旋转也有所不同。在 2D 中,旋转轴始终垂直于 x/y 平面,即位于 z 轴上。在 3D 中,旋转轴可以位于 x、 y 或 z 轴中的任一轴上。通过设置显示对象的旋转属性和缩放属性,可以让该对象在 3D 空间中移动。 重要概念和术语 以下参考列表包含进行三维图形编程时会遇到的重要术语: 透视 在 2D 平面中将平行线表示成聚合于一个消失点,以创建深度和距离的视觉效果。 投影 制作高维对象的 2D 图像; 3D 投影将 3D 点映射到 2D 平面。 旋转 通过按圆周运动方向移动对象内的每个点来更改对象的方向 (通常也会更改其位置)。 转换 通过平移、旋转、缩放、倾斜或这些操作的组合更改 3D 点或点集。 平移 通过将对象内的每个点向同一方向移动相同的距离来更改对象的位置。 消失点 在以线性透视法表示平行线时,逐渐远离的平行线看似聚合在一起的点。 Vector 三维向量使用笛卡尔坐标 x、 y 和 z 轴表示三维空间中的点或位置。 顶点 角点。 纹理式网格 用于在 3D 空间中定义对象的任意点。 UV 映射 对 3D 表面应用纹理或位图的一种方法。UV 映射将值分配给图像上的坐标,以水平 (U) 轴和垂直 (V) 轴的百分比值 形式表示。 T 值 当对象向当前观察点移近或远离当前观察点时,用来确定 3D 对象大小的比例因子。295ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 剔除 呈现或不呈现带有特定缠绕的曲面。通过使用剔除,您可以隐藏对当前视点不可见的表面。 了解 Flash Player 和 AIR 运行时中的 3D 显示对象 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在 Flash Player 10 之前的 Flash Player 版本以及 Adobe AIR 1.5 之前的 Adobe AIR 版本中,显示对象有 x 和 y 两个属性, 用于在 2D 平面上放置显示对象。从 Flash Player 10 和 Adobe AIR 1.5 开始,每个 ActionScript 显示对象都有一个 z 属性, 利用该属性可以沿 z 轴放置显示对象, z 轴一般用于指示深度或距离。 Flash Player 10 和 Adobe AIR 1.5 引入了对 3D 效果的支持。但是显示对象本质上还是平面的。每个显示对象 (例如 MovieClip 对象或 Sprite 对象)最终会呈示于二维的单一平面上。通过 3D 功能,可在三个维中放置、移动、旋转以及按其他 方式转换这些平面对象,还可管理 3D 点以及将这些点转换为 2D x、y 坐标,这样您就能将 3D 对象投影到 2D 视图上。通过这 些功能,可以模拟出丰富的 3D 效果。 ActionScript 使用的 3D 坐标系与其他坐标系不同。在 ActionScript 中使用 2D 坐标系时,沿 x 轴向右移动过程中, x 的值 增大,而沿 y 轴向下移动过程中, y 的值增大。 3D 坐标系仍遵从这一惯例,但另外添加了 z 轴,该轴的值随着远离视点而增 大。 ActionScript 3D 坐标系中 x、 y 和 z 三条轴的正向。 A. +Z 轴 B. 原点 C. +X 轴 D. +Y 轴 注: 请注意,Flash Player 和 AIR 始终在图层中表示 3D。也就是说,如果对象 A 在显示列表中位于对象 B 的前面,则无论这 两个对象的 z 轴值为多少,Flash Player 或 AIR 都始终将 A 呈示在 B 的前面。若要解决显示列表顺序与 z 轴顺序之间的冲突, 可使用 transform.getRelativeMatrix3D() 方法进行保存,然后重新对 3D 显示对象的图层排序。有关详细信息,请参阅第 303 页 的 “ 使用 Matrix3D 对象重新排序显示 ”。 以下 ActionScript 类支持与 3D 相关的新功能: 1 flash.display.DisplayObject 类包含 z 属性和新的旋转和缩放属性,这些属性用于操作 3D 空间中的显示对象。 DisplayObject.local3DToGlobal() 方法提供了一种将 3D 几何图形投影到 2D 平面的简单方式。 2 flash.geom.Vector3D 类可用作管理 3D 点的数据结构。该类还支持矢量数学运算。 3 flash.geom.Matrix3D 类支持复杂的 3D 几何转换,例如旋转、缩放和平移。 4 flash.geom.PerspectiveProjection 类控制着将 3D 几何图形映射到 2D 视图的相关参数。 A C B (0,0,0) D296ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 在 ActionScript 中,有两种不同的模拟 3D 图像的方式: 1 在 3D 空间中排列平面对象并进行动画处理。这种方式需要使用显示对象的 x、 y 和 z 属性来对显示对象进行动画处理,或 者使用 DisplayObject 类设置旋转和缩放属性。使用 DisplayObject.transform.matrix3D 对象可以实现更为复杂的运 动。DisplayObject.transform.perspectiveProjection 对象可自定义显示对象在 3D 透视中的绘制方式。如果需要对主要 包含平面的 3D 对象进行动画处理,可以使用这种方式。这种方式的例子包括 3D 图库或者 3D 空间中排列的 2D 动画对象。 2 从 3D 几何图形生成 2D 三角形,然后用纹理呈示这些三角形。要使用这种方式,必须首先定义和管理有关 3D 对象的数 据,然后将这些数据转换成要呈示的 2D 三角形。可以将位图纹理映射到这些三角形,然后使用 Graphics.drawTriangles() 方法将三角形绘制为图形对象。这种方式的例子包括从文件中加载 3D 模型数据并将模型呈示到屏幕上,或以三角形网格形 式生成和绘制 3D 图形。 创建和移动 3D 显示对象 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 若要将 2D 显示对象转换为 3D 显示对象,可将其 z 属性明确设置为一个数值。如果为 z 属性指定一个值,则会为显示对象创建 一个新的 Transform 对象。设置 DisplayObject.rotationX 或 DisplayObject.rotationY 属性也会创建新的 Transform 对象。 Transform 对象包含 Matrix3D 属性,该属性控制显示对象在 3D 空间中的表示方式。 下面的代码设置名为 “leaf” 的显示对象的坐标: leaf.x = 100; leaf.y = 50; leaf.z = -30; 在 leaf 的 Transform 对象的 matrix3D 属性中,可以查看这些值以及从这些值派生的属性: var leafMatrix:Matrix3D = leaf.transform.matrix3D; trace(leafMatrix.position.x); trace(leafMatrix.position.y); trace(leafMatrix.position.z); trace(leafMatrix.position.length); trace(leafMatrix.position.lengthSquared); 有关 Transform 对象的属性的信息,请参阅 Transform 类。有关 Matrix3D 对象的属性的信息,请参阅 Matrix3D 类。 在 3D 空间中移动对象 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 通过更改对象的 x、 y 或 z 属性的值,可以在 3D 空间中移动对象。如果更改 z 属性的值,对象看起来就会相应地靠近或远离观 察者。 下面的代码在响应事件时,通过更改两个椭圆的 z 属性的值,沿着各自的 z 轴前后移动这两个椭圆。 ellipse2 的移动速度比 ellipse1 快:其 z 属性针对每个 Frame 事件增加 20 倍,而 ellipse1 的 z 属性增加 10 倍:297ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 var depth:int = 1000; function ellipse1FrameHandler(e:Event):void { ellipse1Back = setDepth(e, ellipse1Back); e.currentTarget.z += ellipse1Back * 10; } function ellipse2FrameHandler(e:Event):void { ellipse2Back = setDepth(e, ellipse1Back); e.currentTarget.z += ellipse1Back * 20; } function setDepth(e:Event, d:int):int { if(e.currentTarget.z > depth) { e.currentTarget.z = depth; d = -1; } else if (e.currentTarget.z < 0) { e.currentTarget.z = 0; d = 1; } } 在 3D 空间中旋转对象 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 可以通过三种方式旋转对象,具体采用哪一种取决于设置对象的 rotationX、 rotationY 和 rotationZ 这三个旋转属性的方式。 下图显示两个未旋转的正方形: 下一个图显示两个正方形,它们在正方形容器的 rotationY 属性增大时在 y 轴上旋转。通过旋转这两个正方形的容器或父显示对 象,可以旋转这两个正方形: container.rotationY += 10;298ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 下一个图显示当设置正方形容器的 rotationX 属性时发生的变化。此操作会在 x 轴上旋转正方形。 下一个图显示当增大正方形容器的 rotationZ 属性时发生的变化。此操作会在 z 轴上旋转正方形。 显示对象可以在 3D 空间中同时移动和旋转。 将 3D 对象投影到 2D 视图上 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 flash.geom 包中的 PerspectiveProjection 类提供了一种简单在 3D 空间中移动显示对象时应用基本透视的简单方式。 如果未明确创建 3D 空间的透视投影,3D 引擎将使用默认的 PerspectiveProjection 对象,该对象存在于根上并会传播到其所 有子项上。 用于定义 PerspectiveProjection 对象如何显示 3D 空间的三个属性是: • fieldOfView • projectionCenter • focalLength 修改 fieldOfView 的值会导致自动修改 focalLength 的值,反之亦然,因为这两个属性相互依赖。 如果给定 fieldOfView 值,用于计算 focalLength 的值的公式为: focalLength = stageWidth/2 * (cos(fieldOfView/2) / sin(fieldOfView/2) 通常,您需要明确修改 fieldOfView 属性。 视野 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 通过操作 PerspectiveProjection 类的 fieldOfView 属性,可以使逐渐靠近观察者的 3D 显示对象变大,而使逐渐远离观察者的 对象变小。 fieldOfView 属性指定一个介于 0 到 180 度的角度,该角度确定透视投影的强度。该值越大,沿 z 轴移动的显示对象的扭曲程度 就越大。如果 fieldOfView 值较小,则缩放程度较低,使对象看起来在空间中只是稍稍后移。如果 fieldOfView 值较大,则会导 致较大的扭曲,并显示为较大的移动。如果达到最大值 179.9999... 度,则会出现极端的鱼眼摄像头镜头效果。 fieldOfView 的 最大值为 179.9999...,最小值为 0.00001...。精确的 0 和 180 值是非法值。299ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 投影中心 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 projectionCenter 属性表示透视投影的消失点。该属性作为相对于舞台左上角默认注册点 (0,0) 的偏移量。 当对象逐渐远离观察者时,该对象将朝消失点倾斜直到最终消失。想象一下无限长的走廊。当朝走廊远处看时,两边的墙壁将 聚合到走廊远处的消失点。 如果消失点位于舞台的中心,则走廊将消失于该中心点。projectionCenter 属性的默认值是舞台的中心。例如,如果希望元素出 现在舞台的左边,而 3D 区域出现在右边,可将 projectionCenter 设置为舞台右边的点,使之成为 3D 查看区域的消失点。 焦距 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 focalLength 属性表示视点原点 (0,0,0) 与显示对象在 z 轴上的位置之间的距离。 较长的焦距相当于视野较窄、对象间距离经过压缩的摄远镜头。较短的焦距相当于广角镜头,可获得较宽的视野和较大的扭 曲。中等的焦距相当于肉眼所见的效果。 通常,当显示对象移动时, focalLength 属性会在透视转换过程中动态重新进行计算,不过您可以明确设置该属性。 默认透视投影值 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在根上创建的默认 PerspectiveProjection 对象具有以下值: • fieldOfView:55 • perspectiveCenter:stagewidth/2, stageHeight/2 • focalLength:stageWidth/ 2 * ( cos(fieldOfView/2) / sin(fieldOfView/2) ) 如果您没有创建自己的 PerspectiveProjection 对象,则默认使用这些值。 如果要自行修改 projectionCenter 和 fieldOfView 属性,则可以实例化您自己的 PerspectiveProjection 对象。在这种情况下, 新建对象的默认值如下 (假设默认舞台大小为 500 x 500): • fieldOfView:55 • perspectiveCenter:250,250 • focalLength: 480.24554443359375 示例:透视投影 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 下面的示例演示如何使用透视投影来创建 3D 空间。该示例演示如何通过 projectionCenter 属性来修改消失点和更改空间的透视 投影。进行这种修改后,将强制重新计算 focalLength 和 fieldOfView (及其相关的 3D 空间扭曲)。 此示例: 1 创建一个名为 center 的 sprite,作为包含十字准线的圆 2 将 center sprite 的坐标指定给根的 transform 属性的 perspectiveProjection 属性的 projectionCenter 属性300ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 3 为鼠标事件添加事件侦听器,用于调用修改 projectionCenter 的处理程序,以便跟踪 center 对象的位置 4 创建四个折叠样式的框,这四个框将形成透视空间的墙壁 在测试此示例时, ProjectionDragger.swf 将圆拖动到不同的位置。消失点将跟随圆移动,直到释放圆时才固定下来。在移动 投影中心使其远离舞台中心时,观察包围空间的框所发生的拉伸和出现的扭曲。 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。在 Samples/ProjectionDragger 文件夹中可以找到 ProjectionDragger 应用程序文件。 package { import flash.display.Sprite; import flash.display.Shape; import flash.geom.Point; import flash.events.*; public class ProjectionDragger extends Sprite { private var center : Sprite; private var boxPanel:Shape; private var inDrag:Boolean = false; public function ProjectionDragger():void { createBoxes(); createCenter(); } public function createCenter():void { var centerRadius:int = 20; center = new Sprite(); // circle center.graphics.lineStyle(1, 0x000099); center.graphics.beginFill(0xCCCCCC, 0.5); center.graphics.drawCircle(0, 0, centerRadius); center.graphics.endFill(); // cross hairs center.graphics.moveTo(0, centerRadius); center.graphics.lineTo(0, -centerRadius); center.graphics.moveTo(centerRadius, 0); center.graphics.lineTo(-centerRadius, 0); center.x = 175; center.y = 175; center.z = 0; this.addChild(center); center.addEventListener(MouseEvent.MOUSE_DOWN, startDragProjectionCenter); center.addEventListener(MouseEvent.MOUSE_UP, stopDragProjectionCenter); center.addEventListener( MouseEvent.MOUSE_MOVE, doDragProjectionCenter); root.transform.perspectiveProjection.projectionCenter = new Point(center.x, center.y); } public function createBoxes():void { // createBoxPanel(); var boxWidth:int = 50; var boxHeight:int = 50; var numLayers:int = 12; var depthPerLayer:int = 50; // var boxVec:Vector. = new Vector.(numLayers); for (var i:int = 0; i < numLayers; i++) 301ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 { this.addChild(createBox(150, 50, (numLayers - i) * depthPerLayer, boxWidth, boxHeight, 0xCCCCFF)); this.addChild(createBox(50, 150, (numLayers - i) * depthPerLayer, boxWidth, boxHeight, 0xFFCCCC)); this.addChild(createBox(250, 150, (numLayers - i) * depthPerLayer, boxWidth, boxHeight, 0xCCFFCC)); this.addChild(createBox(150, 250, (numLayers - i) * depthPerLayer, boxWidth, boxHeight, 0xDDDDDD)); } } public function createBox(xPos:int = 0, yPos:int = 0, zPos:int = 100, w:int = 50, h:int = 50, color:int = 0xDDDDDD):Shape { var box:Shape = new Shape(); box.graphics.lineStyle(2, 0x666666); box.graphics.beginFill(color, 1.0); box.graphics.drawRect(0, 0, w, h); box.graphics.endFill(); box.x = xPos; box.y = yPos; box.z = zPos; return box; } public function startDragProjectionCenter(e:Event) { center.startDrag(); inDrag = true; } public function doDragProjectionCenter(e:Event) { if (inDrag) { root.transform.perspectiveProjection.projectionCenter = new Point(center.x, center.y); } } public function stopDragProjectionCenter(e:Event) { center.stopDrag(); root.transform.perspectiveProjection.projectionCenter = new Point(center.x, center.y); inDrag = false; } } } 对于更加复杂的透视投影,请使用 Matrix3D 类。 执行复杂的 3D 转换 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 使用 Matrix3D 类可以转换坐标空间内的 3D 点,也可以将 3D 点从一个坐标空间映射到另一个坐标空间。 无需了解矩阵数学,即可使用 Matrix3D 类。大多数常见的转换操作都可以通过该类的方法进行处理。您不必担心如何明确设 置或计算矩阵中每个元素的值。302ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 将显示对象的 z 属性设置为数值后,可以使用该显示对象的 Transform 对象的 Matrix3D 属性来检索显示对象的转换矩阵: var leafMatrix:Matrix3D = this.transform.matrix3D; 您可以用 Matrix3D 对象的方法对显示对象执行平移、旋转、缩放和透视投影。 使用 Vector3D 类及其 x、 y 和 z 属性可管理 3D 点。该类还可以表示具有方向和大小的物理空间矢量。通过 Vector3D 类的 方法,可以执行有关空间矢量的常见计算,例如加法、点积和叉积计算。 注: Vector3D 类与 ActionScript Vector 类无关。Vector3D 类包含的属性和方法用于定义和操作 3D 点,而 Vector 类则支 持类型对象数组。 创建 Matrix3D 对象 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 有三种主要的创建或检索 Matrix3D 对象的方式: • 使用 Matrix3D() 构造函数方法实例化新的矩阵。 Matrix3D() 构造函数使用包含 16 个数值的 Vector 对象,并将每个值分别 放入一个矩阵单元格中。例如: var rotateMatrix:Matrix3D = new Matrix3D(1,0,0,1, 0,1,0,1, 0,0,1,1, 0,0,0,1); • 设置显示对象的 z 属性的值。然后,从该对象的 transform.matrix3D 属性检索转换矩阵。 • 通过对根显示对象调用 perspectiveProjection.tomatrix3D() 方法,检索用于控制舞台上 3D 对象显示的 Matrix3D 对象。 应用多种 3D 转换 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 通过 Matrix3D 对象,可以一次应用多种 3D 转换。例如,如果要旋转、缩放然后移动立方体,可以对立方体的每个点分别应 用这三种转换。但是,还有一种高效得多的方法,即在一个 Matrix3D 对象中预先计算多种转换,然后对每个点执行一次矩阵 转换。 注: 矩阵转换的应用顺序非常重要。矩阵运算的顺序是不能交换的。例如,先应用旋转再应用平移与先应用平移再应用旋转, 二者的结果是不同的。 下面的示例演示执行多种 3D 转换的两种方式。 package { import flash.display.Sprite; import flash.display.Shape; import flash.display.Graphics; import flash.geom.*; public class Matrix3DTransformsExample extends Sprite { private var rect1:Shape; private var rect2:Shape; public function Matrix3DTransformsExample():void { var pp:PerspectiveProjection = this.transform.perspectiveProjection; pp.projectionCenter = new Point(275,200); this.transform.perspectiveProjection = pp; rect1 = new Shape(); rect1.x = -70; rect1.y = -40; 303ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 rect1.z = 0; rect1.graphics.beginFill(0xFF8800); rect1.graphics.drawRect(0,0,50,80); rect1.graphics.endFill(); addChild(rect1); rect2 = new Shape(); rect2.x = 20; rect2.y = -40; rect2.z = 0; rect2.graphics.beginFill(0xFF0088); rect2.graphics.drawRect(0,0,50,80); rect2.graphics.endFill(); addChild(rect2); doTransforms(); } private function doTransforms():void { rect1.rotationX = 15; rect1.scaleX = 1.2; rect1.x += 100; rect1.y += 50; rect1.rotationZ = 10; var matrix:Matrix3D = rect2.transform.matrix3D; matrix.appendRotation(15, Vector3D.X_AXIS); matrix.appendScale(1.2, 1, 1); matrix.appendTranslation(100, 50, 0); matrix.appendRotation(10, Vector3D.Z_AXIS); rect2.transform.matrix3D = matrix; } } } 在 doTransforms() 方法中,第一个代码块使用 DisplayObject 属性更改矩形形状的旋转、缩放和位置。第二个代码块使用 Matrix3D 类的方法执行相同的转换。 使用 Matrix3D 方法的主要优点在于,所有计算都是在矩阵中提前执行的,然后这些计算只需对显示对象应用一次 (前提是设 置了显示对象的 transform.matrix3D 属性)。通过设置 DisplayObject 属性可使源代码更易于阅读。但是,每次设置旋转和缩 放属性后,会导致进行大量计算并更改显示对象的多个属性。 如果您的代码要多次对显示对象应用相同的复杂转换,应将 Matrix3D 对象保存为变量,然后反复应用该变量。 使用 Matrix3D 对象重新排序显示 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 如前所述,显示列表中显示对象的层叠顺序确定了对象的显示顺序,这些对象的相对 z 轴值对显示顺序没有影响。如果您的动 画将显示对象的属性转换为一种与显示列表中的顺序不同的顺序,则观察者看到的显示对象层叠顺序与 z 轴层叠顺序不一致。 因此,在视觉上应当远离观察者的对象可能反而会靠近观察者。 为确保 3D 显示对象的层叠顺序对应于对象的相对深度,请使用如下方法: 1 使用 Transform 对象的 getRelativeMatrix3D() 方法获取子级 3D 显示对象的相对 z 轴值。 2 使用 removeChild() 方法从显示列表中删除对象。 3 根据显示对象的相对 z 轴值对显示对象进行排序。 4 使用 addChild() 方法以相反顺序将子对象添加到显示列表中。304ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 这种重新排序方法可确保您的对象按照各自的相对 z 轴值进行显示。 下面的代码将 3D 框的六面设置为正确的显示顺序。这段代码对经过旋转的框的各面进行重新排序: public var faces:Array; . . . public function ReorderChildren() { for(var ind:uint = 0; ind < 6; ind++) { faces[ind].z = faces[ind].child.transform.getRelativeMatrix3D(root).position.z; this.removeChild(faces[ind].child); } faces.sortOn("z", Array.NUMERIC | Array.DESCENDING); for (ind = 0; ind < 6; ind++) { this.addChild(faces[ind].child); } } 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。在 Samples/ReorderByZ 文件夹中可以找到这些应用程序文件。 通过三角形获得 3D 效果 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在 ActionScript 中,使用 Graphics.drawTriangles() 方法执行位图转换,因为 3D 模型由空间中的一系列三角形表示。(但是, Flash Player 和 AIR 不支持深度缓冲,因此显示对象在本质上仍然是平面的,即 2D。这一点在第 295 页的 “ 了解 Flash Player 和 AIR 运行时中的 3D 显示对象 ” 中进行了说明。)Graphics.drawTriangles() 方法通过一组坐标来绘制三角形路径,它 与 Graphics.drawPath() 方法类似。 若要熟悉 Graphics.drawPath() 方法的使用,请参阅第 197 页的 “ 绘制路径 ”。 Graphics.drawTriangles() 方法使用 Vector. 来指定三角形路径的点位置: drawTriangles(vertices:Vector., indices:Vector. = null, uvtData:Vector. = null, culling:String = "none"):void drawTriangles() 的第一个参数是唯一的必需参数:vertices 参数。该参数是由定义坐标的数字组成的矢量,通过该矢量即可绘制 三角形。每三组坐标 (六个数字)表示一个三角形路径。如果没有 indices 参数,矢量的长度应始终为六的倍数,因为每个三 角形都需要三个坐标对 (三组 x/y 值对)。例如: graphics.beginFill(0xFF8000); graphics.drawTriangles( Vector.([ 10,10, 100,10, 10,100, 110,10, 110,100, 20,100])); 这些三角形不共享任何点,但是如果有共享点,就可以使用第二个 drawTriangles() 参数 indices 来对多个三角形重复使用 vertices 矢量中的值。 使用 indices 参数时,请注意, indices 值是点索引,而不是直接与 vertices 数组元素相关的索引。也就是说, vertices 矢量中由 indices 定义的索引实际上是除以 2 后的实际索引。例如,对于 vertices 矢量的第三个点,即使该点的第一个数值从矢量索引 4 开始,也使用 indices 值 2。 例如,使用 indices 参数合并两个三角形使二者共享对边:305ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 graphics.beginFill(0xFF8000); graphics.drawTriangles( Vector.([10,10, 100,10, 10,100, 100,100]), Vector.([0,1,2, 1,3,2])); 请注意,尽管正方形现在是通过两个三角形绘制的,但在 vertices 矢量中只指定了四个点。通过使用 indices,两个三角形共享 的两点将由每个三角形重复使用。这样可以将顶点总数从 6 (12 个数字)减少为 4 (8 个数字): 使用 vertices 参数通过两个三角形绘制的正方形 对于较大的三角形网格,这种方法非常有用,因为这种情况下大多数点由多个三角形共享。 所有填充方式都可应用于三角形。填充应用于三角形网格的方式与应用于其他形状的方式是相同的。 转换位图 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 位图转换可在三维对象上提供透视视觉效果或 “ 纹理 ”。具体而言,您可以朝消失点的方向扭曲位图,这样图像在朝消失点方 向移动时会出现收缩效果。或者,您可以使用二维位图为三维对象创建表面,从而提供纹理视觉效果或将三维对象 “ 包裹 ” 起 来。 使用消失点的二维表面和用位图包裹的三维对象。 UV 映射 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 一旦开始处理纹理,您就要使用 drawTriangles() 的 uvtData 参数。此参数用于为位图填充设置 UV 映射。 UV 映射是一种纹理化对象的方法。它依赖于两个值:U 水平 (x) 值和 V 垂直 (y) 值。这两个值不是基于像素值,而是基于百 分比。 0 U 和 0 V 表示图像的坐上角, 1 U 和 1 V 表示右下角: 01 23306ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 位图图像上的 UV 0 和 1 位置 可以为三角形的矢量指定 UV 坐标,从而将矢量自身关联到图像上的相应位置: 位图图像的三角形区域的 UV 坐标 UV 值与三角形的点保持一致: 三角形的顶点移动且位图发生扭曲,从而使单个点的 UV 值保持不变 由于 ActionScript 3D 转换应用于与位图关联的三角形,位图图像将根据 UV 值应用于三角形。因此,不要使用矩阵运算,而 应通过设置或调整 UV 值来实现三维效果。 Graphics.drawTriangles() 方法也接受关于三维转换的一条可选信息:T 值。uvtData 中的 T 值表示 3D 透视,更具体地说,表 示相关顶点的缩放系数。 UVT 映射向 UV 映射加入了透视修正处理。例如,如果将对象放置在 3D 空间中远离视点的位置, 使之显示为原始大小的 50%,则该对象的 T 值为 0.5。因为在 3D 空间中是通过绘制三角形来表示对象的,所以对象在 z 轴上 的位置确定对象的 T 值。用于确定 T 值的等式为: T = focalLength/(focalLength + z); 在该等式中, focalLength 表示焦距或计算得出的 “ 屏幕 ” 位置,它决定了视图中提供的透视大小。307ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 焦距与 z 值 A. 视点 B. 屏幕 C. 3D 对象 D. focalLength 值 E. z 值 T 值用于缩放基本形状,使这些形状看起来更远。该值通常用于将 3D 点转换为 2D 点。而对于 UVT 数据,它也用于在透视 三角形内的点之间缩放位图。 在定义 UVT 值时,T 值紧跟在为顶点定义的 UV 值后面。纳入 T 之后,uvtData 参数中的每三个值(U、V 和 T)与 vertices 参数中的每两个值 (x 和 y)相匹配。在只有 UV 值的情况下, uvtData.length == vertices.length。在加入 T 值的情况下, uvtData.length = 1.5*vertices.length。 下面的示例演示使用 UVT 数据在 3D 空间中旋转平面。本例使用了一幅名为 ocean.jpg 的图像和一个 “ 帮助器 ” 类 ImageLoader,该类用于加载 ocean.jpg 图像以便将其分配给 BitmapData 对象。 下面是 ImageLoader 类的源代码 (请将此代码保存到命名为 ImageLoader.as 的文件中): D E BA C308ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 package { import flash.display.* import flash.events.*; import flash.net.URLRequest; public class ImageLoader extends Sprite { public var url:String; public var bitmap:Bitmap; public function ImageLoader(loc:String = null) { if (loc != null){ url = loc; loadImage(); } } public function loadImage():void{ if (url != null){ var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete); loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIoError); var req:URLRequest = new URLRequest(url); loader.load(req); } } private function onComplete(event:Event):void { var loader:Loader = Loader(event.target.loader); var info:LoaderInfo = LoaderInfo(loader.contentLoaderInfo); this.bitmap = info.content as Bitmap; this.dispatchEvent(new Event(Event.COMPLETE)); } private function onIoError(event:IOErrorEvent):void { trace("onIoError: " + event); } } } 下面的 ActionScript 用三角形、 UV 映射和 T 值使图像获得这样的显示效果:图像朝着消失点逐渐收缩并不断旋转。将此代 码保存到命名为 Spinning3dOcean.as 的文件中: package { import flash.display.* import flash.events.*; import flash.utils.getTimer; public class Spinning3dOcean extends Sprite { // plane vertex coordinates (and t values) var x1:Number = -100,y1:Number = -100,z1:Number = 0,t1:Number = 0; var x2:Number = 100,y2:Number = -100,z2:Number = 0,t2:Number = 0; var x3:Number = 100,y3:Number = 100,z3:Number = 0,t3:Number = 0; var x4:Number = -100,y4:Number = 100,z4:Number = 0,t4:Number = 0; var focalLength:Number = 200; // 2 triangles for 1 plane, indices will always be the same var indices:Vector.; var container:Sprite; var bitmapData:BitmapData; // texture var imageLoader:ImageLoader; public function Spinning3dOcean():void { indices = new Vector.(); indices.push(0,1,3, 1,2,3); 309ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 container = new Sprite(); // container to draw triangles in container.x = 200; container.y = 200; addChild(container); imageLoader = new ImageLoader("ocean.jpg"); imageLoader.addEventListener(Event.COMPLETE, onImageLoaded); } function onImageLoaded(event:Event):void { bitmapData = imageLoader.bitmap.bitmapData; // animate every frame addEventListener(Event.ENTER_FRAME, rotatePlane); } function rotatePlane(event:Event):void { // rotate vertices over time var ticker = getTimer()/400; z2 = z3 = -(z1 = z4 = 100*Math.sin(ticker)); x2 = x3 = -(x1 = x4 = 100*Math.cos(ticker)); // calculate t values t1 = focalLength/(focalLength + z1); t2 = focalLength/(focalLength + z2); t3 = focalLength/(focalLength + z3); t4 = focalLength/(focalLength + z4); // determine triangle vertices based on t values var vertices:Vector. = new Vector.(); vertices.push(x1*t1,y1*t1, x2*t2,y2*t2, x3*t3,y3*t3, x4*t4,y4*t4); // set T values allowing perspective to change // as each vertex moves around in z space var uvtData:Vector. = new Vector.(); uvtData.push(0,0,t1, 1,0,t2, 1,1,t3, 0,1,t4); // draw container.graphics.clear(); container.graphics.beginBitmapFill(bitmapData); container.graphics.drawTriangles(vertices, indices, uvtData); } } } 若要测试此示例,请在名为 “ocean.jpg” 的图像所在的目录中保存这两个类文件。您可以看到原始位图如何转换为在 3D 空间 中消失于远处并不断旋转的效果。 剔除 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 剔除是一个过程,用于确定三维对象的哪些表面因对当前视点不可见而不应被渲染器所呈示。在 3D 空间中,三维对象 “ 背面 ” 的表面对视点不可见:310ACTIONSCRIPT 3.0 开发人员指南 在三维 (3D) 环境中工作 上次更新 2014/12/1 3D 对象的背面对视点不可见。 A. 视点 B. 3D 对象 C. 三维对象的背面 从本质上讲,不管三角形的大小、形状或位置如何,所有三角形都会始终呈示。剔除能确保 Flash Player 或 AIR 正确呈示 3D 对象。此外,为了减少呈示周期,有时您会希望渲染器跳过某些三角形。考虑在空间中旋转的立方体。在任何给定时间,您看 到的立方体的面数不会超过三个面,这是因为不可见的面朝向立方体背面的其他方向。因为这些面不可见,所以渲染器不应绘 制它们。如果不用剔除, Flash Player 或 AIR 就既要绘制正面也要绘制背面。 立方体的某些面对当前视点不可见 因此, Graphics.drawTriangles() 方法采用第四个参数来建立剔除值: public function drawTriangles(vertices:Vector., indices:Vector. = null, uvtData:Vector. = null, culling:String = "none"):void 该剔除参数是来自 TriangleCulling 枚举类的值:TriangleCulling.NONE、 TriangleCulling.POSITIVE 和 TriangleCulling.NEGATIVE。这些值与定义对象表面的三角形路径的方向有关。用于确定剔除的 ActionScript API 假设 3D 形状的所有外向三角形都是以同一路径方向绘制的。一旦三角形面经过旋转后,其路径方向也会改变。此时可以剔除 (不呈 示)该三角形。 因此,如果 TriangleCulling 值为 POSITIVE,则会移除正向路径方向 (顺时针)的三角形。如果 TriangleCulling 值为 NEGATIVE,则会移除负向路径方向 (逆时针)的三角形。对于立方体,朝前的表面具有正向路径方向,而朝后的表面具有负 向路径方向: “ 展开 ” 的立方体,用以显示路径方向。当立方体 “ 恢复原状 ” 后,背面路径方向变为相反方向。 若要了解剔除的工作原理,请从前面 第 305 页的 “UV 映射 ” 中的示例开始,将 drawTriangles() 方法的剔除参数设置为 TriangleCulling.NEGATIVE: container.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NEGATIVE); 请注意,在对象旋转时,未呈现图像的 “ 背面 ”。 BA C311 上次更新 2014/12/1 第 20 章 : 文本使用基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 Adobe® Flash® Player 或 Adobe® AIR™ 中,若要在屏幕上显示文本,可以使用 TextField 类的实例或使用 Flash 文本引擎 类。这些类可用于执行文本的创建、显示和格式设置。或者,您可以使用 Text Layout Framework (TLF),一种便于使用的 基于 Flash 文本引擎类的组件库。在移动设备上,您可以使用 StageText 类进行文本输入。 您可以为文本字段确定具体内容,或者指定文本来源,然后设置该文本的外观。还可以在用户输入文本或单击超文本链接时响 应用户事件。 您可以使用 TextField 类,也可以使用 Flash 文本引擎类在 Flash Player 和 AIR 中显示和管理文本。可使用 TextField 类创 建文本对象以显示和输入文本。 TextField 类为其他基于文本的组件提供了基础,例如 TextArea 和 TextInput。可以使用 TextFormat 类来设置 TextField 对象的字符和段落格式,可以使用 Textfield.styleSheet 属性和 StyleSheet 类来应用层叠样 式表 (CSS)。可将 HTML 格式的文本直接分配给文本字段, HTML 格式的文本可包含嵌入的媒体 (影片剪辑、 SWF 文件、 GIF 文件、 PNG 文件和 JPEG 文件)。 从 Flash Player 10 和 Adobe AIR 1.5 开始提供的 Flash 文本引擎为文本度量、格式设置和双向文本的复杂控制提供底层支 持。它还提供改进的文本流和增强的语言支持。尽管可以使用 Flash 文本引擎创建和管理文本元素,但设计 Flash 文本引擎的 主要目的在于为创建文本处理组件提供基础,并且它要求较高的编程技术。 Text Layout Framework 提供了一种比较容易的 使用该新文本引擎的高级功能的方法,它包括一个基于 Flash 文本引擎的文本处理组件。Text Layout Framework 是完全内置 于 ActionScript 3.0 的可扩展库。您可以使用现有的 TLF 组件,或者使用框架构建您自己的文本组件。 AIR 3 中将开始引入 StageText 类,以提供本地文本输入字段。由于此字段是设备操作系统提供的,它将为最熟悉设备的用户 提供相关经验。 StageText 实例不是显示对象。您不需要将其添加到显示列表,而是为实例分配一个舞台和一个位于此舞台上 的称为视口的显示区域。 StageText 实例显示在显示对象的前面。 有关这些主题的详细信息,请参阅: • 第 313 页的 “ 使用 TextField 类 ” • 第 334 页的 “ 使用 Flash 文本引擎 ” • 第 360 页的 “ 使用 Text Layout Framework” • 使用 StageText 的本机文本输入 重要概念和术语 以下参考列表包含处理文本涉及的重要术语: 级联样式表 标准语法,用于指定以 XML (或 HTML)格式构建的内容的样式和格式设置。 设备字体 用户计算机中安装的一种字体。 动态文本字段 其内容可由 ActionScript 更改,而不能通过用户输入进行更改的文本字段。 嵌入字体 其字符轮廓数据存储在应用程序 SWF 文件中的一种字体。 HTML 文本 使用 ActionScript 输入到文本字段中的文本内容,包括 HTML 格式标签和实际文本内容。 输入文本字段 其内容既可通过用户输入进行更改也可通过 ActionScript 进行更改的文本字段。 字距微调 调整两个字符之间的间距,使字与字的间距比例更佳,文字更易于阅读。 静态文本字段 在创作工具中创建的文本字段,无法在运行 SWF 文件时更改其内容。312ACTIONSCRIPT 3.0 开发人员指南 文本使用基础知识 上次更新 2014/12/1 文本行量度 文本字段中文本内容不同部分的大小的量度,如文本的基线、字符顶部的高度、下行字符 (某些小写字母延伸到基 线以下的部分)的大小,等等。 跟踪 调整字母组或文本块之间的间距,以增大或减小密度,使文本更容易阅读。313 上次更新 2014/12/1 第 21 章 : 使用 TextField 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 Adobe® Flash® Player 或 Adobe® AIR™ 中,您可以使用 TextField 类的实例在屏幕上显示文本或创建文本输出字段。 TextField 类是其他基于文本的组件 (如 TextArea 组件或 TextInput 组件)的基础。 文本字段内容可以在 SWF 文件中预先指定、从文本文件或数据库中加载,或由用户在与应用程序交互时输入。在文本字段 内,文本可以显示为呈示的 HTML 内容,并可在其中嵌入图像。创建文本字段的实例后,可以使用 TextFormat 和 StyleSheet 等 flash.text 类控制文本的外观。 flash.text 包几乎包含所有与在 ActionScript 中创建、管理文本和设置文件格式 相关的类。 可以用 TextFormat 对象定义格式设置并将此对象分配给文本字段,以此来设置文本格式。如果文本字段包含 HTML 文本, 则可以对文本字段应用 StyleSheet 对象,以便将样式分配给文本字段内容的特定片段。TextFormat 对象或 StyleSheet 对象包 含定义文本外观 (例如颜色、大小和粗细)的属性。 TextFormat 对象可以将属性分配给文本字段中的所有内容,也可以分配 给某个范围的文本。例如,在同一文本字段中,一个句子可以是粗体的红色文本,而下一个句子可以是斜体的蓝色文本。 除了 flash.text 包中的类以外,您还可以使用 flash.events.TextEvent 类响应与文本相关的用户操作。 更多帮助主题 第 319 页的 “ 指定文本格式 ” 第 314 页的 “ 显示 HTML 文本 ” 第 320 页的 “ 应用层叠样式表 ” 显示文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 虽然 Adobe Flash Builder 和 Flash Professional 等创作工具提供了多种用于显示文本的选项(包括与文本相关的组件或文本 工具),但是以编程方式显示文本的最简单方法还是通过文本字段。 文本类型 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 文本字段中文本的类型根据其来源进行划分: • 动态文本 动态文本包含从外部源 (例如文本文件、 XML 文件以及远程 Web 服务)加载的内容。 • 输入文本 输入文本是指用户输入的任何文本或用户可以编辑的动态文本。可以设置样式表来设置输入文本的格式,或使用 flash.text.TextFormat 类为输入内容指定文本字段的属性。有关详细信息,请参阅第 317 页的 “ 捕获文本输入 ”。 • 静态文本314ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 静态文本只通过 Flash Professional 创建。不能使用 ActionScript 3.0 创建静态文本实例。但是,可以使用 ActionScript 类 (例如 StaticText 和 TextSnapshot)来操作现有的静态文本实例。有关详细信息,请参阅第 324 页的 “ 使用静态文本 ”。 修改文本字段内容 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 可通过将字符串分配给 flash.text.TextField.text 属性来定义动态文本。可以直接将字符串赋予该属性,如下所示: myTextField.text = "Hello World"; 还可以为 text 属性赋予在脚本中定义的变量值,如下例所示: package { import flash.display.Sprite; import flash.text.*; public class TextWithImage extends Sprite { private var myTextBox:TextField = new TextField(); private var myText:String = "Hello World"; public function TextWithImage() { addChild(myTextBox); myTextBox.text = myText; } } } 或者,可以将一个远程变量的值赋予 text 属性。从远程源加载文本值有三种方式: • flash.net.URLLoader 和 flash.net.URLRequest 类可以从本地或远程位置为文本加载变量。 • FlashVars 属性被嵌入到承载 SWF 文件的 HTML 页中,可以包含文本变量的值。 • flash.net.SharedObject 类管理值的永久存储。有关详细信息,请参阅第 602 页的 “ 存储本地数据 ”。 显示 HTML 文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 flash.text.TextField 类具有一个 htmlText 属性,可使用它将您的文本字符串标识为包含用于设置内容格式的 HTML 标签。 如下例所示,必须将您的字符串值赋予 htmlText 属性(而不是 text 属性),以便 Flash Player 或 AIR 将文本呈示为 HTML: var myText:String = "

    This is some content to render as HTML text.

    "; myTextBox.htmlText = myText; Flash Player 和 AIR 支持用于 htmlText 属性的 HTML 标签和实体的一个子集。 “ActionScript 3.0 参考 ” 中的 flash.text.TextField.htmlText 属性描述提供了关于支持的 HTML 标记和实体的详细信息。 一旦您使用 htmlText 属性指定了内容,就可以使用样式表或 textformat 标签来管理内容的格式设置。有关详细信息,请参阅 第 319 页的 “ 设置文本格式 ”。315ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 在文本字段中使用图像 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 将内容显示为 HTML 文本的另一个好处是可以在文本字段中包括图像。可以使用 img 标签引用一个本地或远程图像,并使其 显示在关联的文本字段内。 以下示例将创建一个名为 myTextBox 的文本字段,并在显示的文本中包括一个内容为眼睛的 JPG 图像,该图像与 SWF 文件存 储在同一目录下: package { import flash.display.Sprite; import flash.text.*; public class TextWithImage extends Sprite { private var myTextBox:TextField; private var myText:String = "

    This is some c o n t e n t t o < i > t e s t < / i > a n d < i > s e e < / i > < / p > < p > < i m g src='eye.jpg' width='20' height='20'>

    what can be rendered.

    You should see an eye image and some HTML text.

    "; public function TextWithImage() { myTextBox.width = 200; myTextBox.height = 200; myTextBox.multiline = true; myTextBox.wordWrap = true; myTextBox.border = true; addChild(myTextBox); myTextBox.htmlText = myText; } } } img 标签支持 JPEG、 GIF、 PNG 和 SWF 文件。 在文本字段中滚动文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在许多情况下,文本可能比显示该文本的文本字段长。或者,某个输入字段允许用户输入比字段一次可显示的文本内容更多的 文本。您可以使用 flash.text.TextField 类的与滚动相关的属性来管理过长的内容 (垂直或水平方向)。 与滚动有关的属性包括 TextField.scrollV、TextField.scrollH、maxScrollV 和 maxScrollH。可使用这些属性来响应鼠标单击或按 键等事件。 以下示例将创建一个已设置大小的文本字段,其中包含的文本内容超过了该字段一次可以显示的内容。当用户单击文本字段 时,文本垂直滚动。316ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 package { import flash.display.Sprite; import flash.text.*; import flash.events.MouseEvent; public class TextScrollExample extends Sprite { private var myTextBox:TextField = new TextField(); private var myText:String = "Hello world and welcome to the show. It's really nice to meet you. Take your coat off and stay a while. OK, show is over. Hope you had fun. You can go home now. Don't forget to tip your waiter. There are mints in the bowl by the door. Thank you. Please come again."; public function TextScrollExample() { myTextBox.text = myText; myTextBox.width = 200; myTextBox.height = 50; myTextBox.multiline = true; myTextBox.wordWrap = true; myTextBox.background = true; myTextBox.border = true; var format:TextFormat = new TextFormat(); format.font = "Verdana"; format.color = 0xFF0000; format.size = 10; myTextBox.defaultTextFormat = format; addChild(myTextBox); myTextBox.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownScroll); } public function mouseDownScroll(event:MouseEvent):void { myTextBox.scrollV++; } } } 选择和操作文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 您可以选择动态文本或输入文本。由于 TextField 类的文本选择属性和方法使用索引位置来设置要操作的文本的范围,因此即 使不知道内容,您也可以以编程方式选择动态文本或输入文本。 注: 在 Flash Professional 中,如果对静态文本字段选择了可选选项,则导出并置于显示列表中的文本字段为常规的动态文本 字段。 选择文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 默认情况下, flash.text.TextField.selectable 属性为 true,您可以使用 setSelection() 方法以编程方式选择文本。 例如,您可以将某个文本字段中的特定文本设置成用户单击该文本字段时处于选定状态:317ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 var myTextField:TextField = new TextField(); myTextField.text = "No matter where you click on this text field the TEXT IN ALL CAPS is selected."; myTextField.autoSize = TextFieldAutoSize.LEFT; addChild(myTextField); addEventListener(MouseEvent.CLICK, selectText); function selectText(event:MouseEvent):void { myTextField.setSelection(49, 65); } 同样,如果您想让文本字段中的文本一开始显示时就处于选定状态,可以创建一个在向显示列表中添加该文本字段时调用的事 件处理函数。 捕获用户选择的文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 TextField 的 selectionBeginIndex 和 selectionEndIndex 属性可用于捕获用户当前选择的任何内容,这两个属性为 “ 只读 ” 属 性,因此不能设置为以编程方式选择文本。此外,输入文本字段也可以使用 caretIndex 属性。 例如,以下代码将跟踪用户所选文本的索引值: var myTextField:TextField = new TextField(); myTextField.text = "Please select the TEXT IN ALL CAPS to see the index values for the first and last letters."; myTextField.autoSize = TextFieldAutoSize.LEFT; addChild(myTextField); addEventListener(MouseEvent.MOUSE_UP, selectText); function selectText(event:MouseEvent):void { trace("First letter index position: " + myTextField.selectionBeginIndex); trace("Last letter index position: " + myTextField.selectionEndIndex); } 您可以对所选内容应用 TextFormat 对象属性的集合来更改文本的外观。有关将 TextFormat 属性的集合应用于选定文本的详 细信息,请参阅第 322 页的 “ 设置文本字段内文本范围的格式 ”。 捕获文本输入 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 默认情况下,文本字段的 type 属性设置为 dynamic。如果使用 TextFieldType 类将 type 属性设置为 input,则可以收集用户输 入并保存该值以便在应用程序的其他部分使用。对于表单以及希望用户定义可用于程序中其他位置的文本值的任何应用程序而 言,输入文本字段都十分有用。 例如,以下代码会创建一个名为 myTextBox 的输入文本字段。当用户在字段中输入文本时,会触发 textInput 事件。名为 textInputCapture 的事件处理函数会捕获输入的文本字符串,并将其赋予一个变量。 Flash Player 或 AIR 会在另一个名为 myOutputBox 的文本字段中显示新文本。318ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 package { import flash.display.Sprite; import flash.display.Stage; import flash.text.*; import flash.events.*; public class CaptureUserInput extends Sprite { private var myTextBox:TextField = new TextField(); private var myOutputBox:TextField = new TextField(); private var myText:String = "Type your text here."; public function CaptureUserInput() { captureText(); } public function captureText():void { myTextBox.type = TextFieldType.INPUT; myTextBox.background = true; addChild(myTextBox); myTextBox.text = myText; myTextBox.addEventListener(TextEvent.TEXT_INPUT, textInputCapture); } public function textInputCapture(event:TextEvent):void { var str:String = myTextBox.text; createOutputBox(str); } public function createOutputBox(str:String):void { myOutputBox.background = true; myOutputBox.x = 200; addChild(myOutputBox); myOutputBox.text = str; } } } 限制文本输入 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 由于输入文本字段经常用于表单或应用程序中的对话框,所以您可能想要限制用户在文本字段中输入的字符的类型,或者甚至 希望将文本隐藏(例如,密码文本)。可以设置 flash.text.TextField 类的 displayAsPassword 属性和 restrict 属性来控制用户输 入。 displayAsPassword 属性只是在用户键入文本时将其隐藏(显示为一系列星号)。当 displayAsPassword 设置为 true 时,“ 剪切 ” 和 “ 复制 ” 命令及其对应的键盘快捷键将不起作用。如下例所示,为 displayAsPassword 属性赋值的过程与为其他属性 (如背 景和颜色)赋值类似:319ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 myTextBox.type = TextFieldType.INPUT; myTextBox.background = true; myTextBox.displayAsPassword = true; addChild(myTextBox); restrict 属性更复杂些,您必须指定允许用户在输入文本字段中键入的字符。可以允许特定字母、数字或字母、数字和字符的范 围。以下代码只允许用户在文本字段中输入大写字母 (不包括数字或特殊字符): myTextBox.restrict = "A-Z"; ActionScript 3.0 使用连字符来定义范围,使用尖号来定义被排除的字符。有关定义输入文本字段中的受限内容的详细信息, 请参阅 “ActionScript 3.0 参考 ” 中的 flash.text.TextField.restrict 属性条目。 注: 如果使用 flash.text.TextField.restrict 属性,运行时会将受限字母自动转换为允许的大小写。如果使用 fl.text.TLFTextField.restrict 属性 (即如果使用 TLF 文本字段),运行时将忽略受限字母。 设置文本格式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 以编程方式设置文本显示的格式设置有多种方式。可以直接在 TextField 实例中设置属性,例如, TextFIeld.thickness、 TextField.textColor 和 TextField.textHeight 属性。也可以使用 htmlText 属性指定文本字段的内容,并使用受支持的 HTML 标 签,如 b、i 和 u。但是您也可以将 TextFormat 对象应用于包含纯文本的文本字段,或将 StyleSheet 对象应用于包含 htmlText 属性的文本字段。使用 TextFormat 和 StyleSheet 对象可以对整个应用程序的文本外观提供最有力的控制和最佳的一致性。可 以定义 TextFormat 或 StyleSheet 对象并将其应用于应用程序中的部分或所有文本字段。 指定文本格式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 您可以使用 TextFormat 类设置多个不同的文本显示属性,并将它们应用于 TextField 对象的整个内容或一定范围的文本。 以下示例对整个 TextField 对象应用一个 TextFormat 对象,并对 TextField 对象中一定范围的文本应用另一个 TextFormat 对象: var tf:TextField = new TextField(); tf.text = "Hello Hello"; var format1:TextFormat = new TextFormat(); format1.color = 0xFF0000; var format2:TextFormat = new TextFormat(); format2.font = "Courier"; tf.setTextFormat(format1); var startRange:uint = 6; tf.setTextFormat(format2, startRange); addChild(tf); TextField.setTextFormat() 方法只影响已显示在文本字段中的文本。如果 TextField 中的内容发生更改,则应用程序可能需要重 新调用 TextField.setTextFormat() 方法以便重新应用格式设置。您也可以设置 TextField 的 defaultTextFormat 属性来指定用户 输入文本所用的格式。320ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 应用层叠样式表 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 文本字段可以包含纯文本或 HTML 格式的文本。纯文本存储在实例的 text 属性中,而 HTML 文本存储在 htmlText 属性中。 您可以使用 CSS 样式声明来定义可应用于多种不同文本字段的文本样式。CSS 样式声明可以在应用程序代码中进行创建,也可 以在运行时从外部 CSS 文件中加载。 flash.text.StyleSheet 类用于处理 CSS 样式。 StyleSheet 类可识别有限的 CSS 属性集合。有关 StyleSheet 类支持的样式属性 的详细列表,请参阅 “ActionScript 3.0 参考 ” 中的 flash.textStylesheet 条目。 如以下示例所示,您可以在代码中创建 CSS,并使用 StyleSheet 对象对 HTML 文本应用这些样式: var style:StyleSheet = new StyleSheet(); var styleObj:Object = new Object(); styleObj.fontSize = "bold"; styleObj.color = "#FF0000"; style.setStyle(".darkRed", styleObj); var tf:TextField = new TextField(); tf.styleSheet = style; tf.htmlText = "Red apple"; addChild(tf); 创建 StyleSheet 对象后,示例代码创建一个简单对象以容纳一组样式声明属性。然后该代码调用 StyleSheet.setStyle() 方法,该 方法将名为 “.darkred” 的新样式添加到样式表中。接着,代码通过将 StyleSheet 对象分配给 TextField styleSheet 属性来应用 样式表格式设置。 要使 CSS 样式生效,应在设置 htmlText 属性之前对 TextField 对象应用样式表。 根据设计,带有样式表的文本字段是不可编辑的。如果您有一个输入文本字段并为其分配一个样式表,则该文本字段将显示样 式表的属性,但不允许用户在其中输入新的文本。而且,您也无法在分配有样式表的文本字段上使用以下 ActionScript API: • TextField.replaceText() 方法 • TextField.replaceSelectedText() 方法 • TextField.defaultTextFormat 属性 • TextField.setTextFormat() 方法 如果某个文本字段已经分配了一个样式表,但后来将 TextField.styleSheet 属性设置为 null,则 TextField.text 和 TextField.htmlText 属性的内容会向它们的内容中添加标签和属性,以结合先前分配的样式表设定的格式。若要保留原始 htmlText 属性,应在将样式表设置为 null 之前将其保存在变量中。 加载外部 CSS 文件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 用于设置格式的 CSS 方法的功能更加强大,您可以在运行时从外部文件加载 CSS 信息。当 CSS 数据位于应用程序本身以外 时,您可以更改应用程序中的文本的可视样式,而不必更改 ActionScript 3.0 源代码。部署完应用程序后,可以通过更改外部 CSS 文件来更改应用程序的外观,而不必重新部署应用程序 SWF 文件。 StyleSheet.parseCSS() 方法可将包含 CSS 数据的字符串转换为 StyleSheet 对象中的样式声明。以下示例显示如何读取外部 CSS 文件并对 TextField 对象应用其样式声明。 首先,下面是要加载的 CSS 文件 (名为 example.css)的内容:321ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 p { font-family: Times New Roman, Times, _serif; font-size: 14; } h1 { font-family: Arial, Helvetica, _sans; font-size: 20; font-weight: bold; } .bluetext { color: #0000CC; } 接下来是加载该 example.css 文件并对 TextField 内容应用样式的类的 ActionScript 代码: package { import flash.display.Sprite; import flash.events.Event; import flash.net.URLLoader; import flash.net.URLRequest; import flash.text.StyleSheet; import flash.text.TextField; import flash.text.TextFieldAutoSize; public class CSSFormattingExample extends Sprite { var loader:URLLoader; var field:TextField; var exampleText:String = "

    This is a headline

    " + "

    This is a line of text. " + "This line of text is colored blue.

    "; public function CSSFormattingExample():void { field = new TextField(); field.width = 300; field.autoSize = TextFieldAutoSize.LEFT; field.wordWrap = true; addChild(field); var req:URLRequest = new URLRequest("example.css"); loader = new URLLoader(); loader.addEventListener(Event.COMPLETE, onCSSFileLoaded); loader.load(req); } public function onCSSFileLoaded(event:Event):void { var sheet:StyleSheet = new StyleSheet(); sheet.parseCSS(loader.data); field.styleSheet = sheet; field.htmlText = exampleText; } } } 加载 CSS 数据后,会执行 onCSSFileLoaded() 方法并调用 StyleSheet.parseCSS() 方法,将样式声明传送给 StyleSheet 对象。322ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 设置文本字段内文本范围的格式 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 flash.text.TextField 类的一个很有用的方法是 setTextFormat() 方法。使用 setTextFormat(),您可以将特定属性分配给文本字 段的部分内容以响应用户输入,例如,需要提醒用户必须输入特定条目的表单,或在用户选择部分文本时提醒用户更改文本字 段内文本段落小节的重点的表单。 以下示例对某一范围的字符使用 TextField.setTextFormat(),以在用户单击文此本字段时更改 myTextField 的部分内容的外观: var myTextField:TextField = new TextField(); myTextField.text = "No matter where you click on this text field the TEXT IN ALL CAPS changes format."; myTextField.autoSize = TextFieldAutoSize.LEFT; addChild(myTextField); addEventListener(MouseEvent.CLICK, changeText); var myformat:TextFormat = new TextFormat(); myformat.color = 0xFF0000; myformat.size = 18; myformat.underline = true; function changeText(event:MouseEvent):void { myTextField.setTextFormat(myformat, 49, 65); } 高级文本呈现 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 3.0 在 flash.text 包中提供多个类来控制所显示文本的属性,包括嵌入字体、消除锯齿设置、 alpha 通道控制及 其他特定设置。“ActionScript 3.0 参考 ” 提供了对这些类和属性(其中包括 CSMSettings、Font 和 TextRenderer 类)的详 细描述。 使用嵌入字体 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当您在应用程序中为 TextField 指定特定字体时, Flash Player 或 AIR 会查找同名的设备字体 (位于用户计算机上的一种字 体)。如果在系统上没有找到该字体,或者用户的字体版本与具有该名称的字体略有差异,则文本显示外观会与预想的情况差 别很大。默认情况下,文本显示为 Times Roman 字体。 若要确保用户看到完全正确的字体,您可以将该字体嵌入到应用程序 SWF 文件中。嵌入字体有很多好处: • 嵌入字体字符是消除锯齿的,特别是对于较大的文本,该字体可以使文本边缘看起来更平滑。 • 可以旋转使用嵌入字体的文本。 • 嵌入字体文本可以产生透明或半透明效果。 • 可以对嵌入字体使用字距调整的 CSS 样式。 使用嵌入字体的最大限制是嵌入字体会增加文件大小或应用程序的下载大小。 将字体文件嵌入到应用程序 SWF 文件中的具体方法因开发环境而异。323ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 嵌入字体后,可以确保 TextField 使用正确的嵌入字体: • 将 TextField 的 embedFonts 属性设置为 true。 • 创建一个 TextFormat 对象,将其 fontFamily 属性设置为嵌入字体的名称,并对 TextField 应用 TextFormat 对象。指定 嵌入字体时, fontFamily 属性应只包含一个名称;该名称不能是用逗号分隔的由多个字体名称构成的列表。 • 如果使用 CSS 样式为 TextField 或组件设置字体,请将 font-family CSS 属性设置为嵌入字体的名称。如果要指定一种嵌入 字体,则 font-family 属性必须包含单一名称,而不能是多个名称的列表。 在 Flash 中嵌入字体 Flash Professional 允许您嵌入系统中已安装的几乎所有字体,包括 TrueType 字体和 Type 1 Postscript 字体。 可以利用多种方法将字体嵌入应用程序,其中包括: • 在舞台上设置 TextField 的字体和样式属性,然后单击 “ 嵌入字体 ” 复选框 • 创建并引用字体元件 • 创建并使用包含嵌入字体元件的运行时共享库 有关如何在应用程序中嵌入字体的详细信息,请参阅 《使用 Flash》中的 “ 动态或输入文本字段的嵌入字体 ”。 在 Flex 中嵌入字体 可以利用多种方法将字体嵌入 Flex 应用程序,其中包括: • 在脚本中使用 [Embed] 元数据标签 • 使用 @font-face 样式声明 • 建立此类字体的类并使用 [Embed] 标签将其嵌入。 在 Flex 应用程序中只能直接嵌入 TrueType 字体。 Type 1 Postscript 等其他格式的字体可以先嵌入到使用 Flash Professional 的 SWF 文件,然后便可在 Flex 应用程序中使用此 SWF 文件。有关在 Flex 中使用 SWF 文件中的嵌入字体的详 细信息,请参阅 《使用 Flex 4》中的 “ 嵌入 SWF 文件中的字体 ”。 更多帮助主题 嵌入字体以实现一致的文本外观 Peter deHaan:嵌入字体 Divillysausages.com:AS3 字体嵌入主类 控制清晰度、粗细和消除锯齿 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 默认情况下,在文本调整大小、更改颜色或在不同背景上显示时, Flash Player 或 AIR 可以确定文本显示控件的设置 (如清 晰度、粗细和消除锯齿)。在某些情况下,如文本很小、很大或显示在各种特别的背景上时,您可能需要保持对这些设置的控 制。可以使用 flash.text.TextRenderer 类及其相关类 (如 CSMSettings 类)来覆盖 Flash Player 或 AIR 的设置。使用这些类 可以精确控制嵌入文本的呈示品质。有关嵌入字体的详细信息,请参阅第 322 页的 “ 使用嵌入字体 ”。 注: 为了设置清晰度、粗细或 gridFitType 属性,或者使用 TextRenderer.setAdvancedAntiAliasingTable() 方法, flash.text.TextField.antiAliasType 属性的值必须是 AntiAliasType.ADVANCED。 以下示例使用名为 myFont 的嵌入字体对显示的文本应用自定义连续笔触调制 (CSM) 属性和格式设置。用户单击显示的文本 时, Flash Player 或 Adobe AIR 会应用自定义设置:324ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 var format:TextFormat = new TextFormat(); format.color = 0x336699; format.size = 48; format.font = "myFont"; var myText:TextField = new TextField(); myText.embedFonts = true; myText.autoSize = TextFieldAutoSize.LEFT; myText.antiAliasType = AntiAliasType.ADVANCED; myText.defaultTextFormat = format; myText.selectable = false; myText.mouseEnabled = true; myText.text = "Hello World"; addChild(myText); myText.addEventListener(MouseEvent.CLICK, clickHandler); function clickHandler(event:Event):void { var myAntiAliasSettings = new CSMSettings(48, 0.8, -0.8); var myAliasTable:Array = new Array(myAntiAliasSettings); TextRenderer.setAdvancedAntiAliasingTable("myFont", FontStyle.ITALIC, TextColorType.DARK_COLOR, myAliasTable); } 使用静态文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 仅在 Flash Professional 中创建静态文本。不能使用 ActionScript 以编程方式对静态文本进行实例化。静态文本非常适用于 简短且不会更改 (动态文本则会更改)的文本。可以将静态文本看作一种图形元素,类似于 Flash Professional 中在舞台上绘 制的圆形或正方形。由于静态文本比动态文本受到更多的限制,ActionScript 3.0 允许使用 StaticText 类读取静态文本的属性 值。另外还可使用 TextSnapshot 类从静态文本中读取值。 使用 StaticText 类访问静态文本字段 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 通常,可使用 Flash Professional 的 “ 动作 ” 面板中的 flash.text.StaticText 类与舞台上放置的静态文本实例交互。也可以在 与包含静态文本的 SWF 文件进行交互的 ActionScript 文件中执行类似工作。但是这两种情况下都不能以编程方式对静态文本 实例进行实例化。在 Flash Professional 中创建静态文本。 若要创建对现有静态文本字段的引用,可以遍历显示列表中的项目并分配一个变量。例如: for (var i = 0; i < this.numChildren; i++) { var displayitem:DisplayObject = this.getChildAt(i); if (displayitem instanceof StaticText) { trace("a static text field is item " + i + " on the display list"); var myFieldLabel:StaticText = StaticText(displayitem); trace("and contains the text: " + myFieldLabel.text); } } 引用某个静态文本字段之后,您可以在 ActionScript 3.0 中使用该字段的属性。下面的代码附加到时间轴上的一个帧,并假设 一个静态文本引用分配有一个名为 myFieldLabel 的变量。相对于 myFieldLabel 的 x 和 y 值放置名为 myField 的动态文本字段, 并再次显示 myFieldLabel 的值。325ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 var myField:TextField = new TextField(); addChild(myField); myField.x = myFieldLabel.x; myField.y = myFieldLabel.y + 20; myField.autoSize = TextFieldAutoSize.LEFT; myField.text = "and " + myFieldLabel.text 使用 TextSnapshot 类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 如果要以编程方式使用现有静态文本实例,可以使用 flash.text.TextSnapshot 类来与 flash.display.DisplayObjectContainer 的 textSnapshot 属性配合工作。也就是说,通过 DisplayObjectContainer.textSnapshot 属性创建 TextSnapshot 实例。然后,可以将方法应用于该实例,以检索值或选择部分静态文本。 例如,请在舞台上放置一个包含文本 “TextSnapshot Example” 的静态文本字段。将下面的 ActionScript 添加到时间轴中的 第 1 帧: var mySnap:TextSnapshot = this.textSnapshot; var count:Number = mySnap.charCount; mySnap.setSelected(0, 4, true); mySnap.setSelected(1, 2, false); var myText:String = mySnap.getSelectedText(false); trace(myText); 如果要在应用程序的其他部分将该文本作为值使用,则 TextSnapshot 类对于从所加载的 SWF 文件中的静态文本字段中获取 文本非常有用。 TextField 示例:报纸风格的文本格式设置 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 “ 新闻布局 ” 示例设置文本的格式,使文本的外观看起来有点象印刷报纸中的素材。输入文本可以包含标题、副标题和素材正 文。在给定显示宽度和高度的情况下,此 “ 新闻布局 ” 示例将会设置标题和副标题的格式,使其占据整个显示区域的宽度。素 材文本分布在两列或更多列中。 此示例演示以下 ActionScript 编程技巧: • 扩展 TextField 类 • 加载并应用外部 CSS 文件 • 将 CSS 样式转换为 TextFormat 对象 • 使用 TextLineMetrics 类获取有关文本显示大小的信息 若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。 “ 新闻布局 ” 应用程序文件位于 Samples/NewsLayout 文件夹中。该应用程序包含以下文件:326ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 读取外部 CSS 文件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 “ 新闻布局 ” 应用程序开始时读取本地 XML 文件中的素材文本。然后,它读取提供标题、副标题和主体文本的格式设置信息 的外部 CSS 文件。 CSS 文件定义三种样式:用于素材的标准段落样式和分别用于标题和副标题的 h1 和 h2 样式。 p { font-family: Georgia, "Times New Roman", Times, _serif; font-size: 12; leading: 2; text-align: justify; indent: 24; } h1 { font-family: Verdana, Arial, Helvetica, _sans; font-size: 20; font-weight: bold; color: #000099; text-align: left; } h2 { font-family: Verdana, Arial, Helvetica, _sans; font-size: 16; font-weight: normal; text-align: left; } 用于读取外部 CSS 文件的方法与第 320 页的 “ 加载外部 CSS 文件 ” 中所述的方法相同。加载 CSS 文件后,应用程序执行 onCSSFileLoaded() 方法,如下所示。 文件 说明 NewsLayout.mxml 或 NewsLayout.fla 适用于 Flex (MXML) 或 Flash (FLA) 的应用程序的用户界面。 com/example/programmingas3/ne wslayout/StoryLayoutComponent.a s 放置 StoryLayout 实例的 Flex UIComponent 类。 com/example/programmingas3/ne wslayout/StoryLayout.as 排列用于显示的所有新闻素材组件的主要 ActionScript 类。 com/example/programmingas3/ne wslayout/FormattedTextField.as 管理本身的 TextFormat 对象的 TextField 类的子类。 com/example/programmingas3/ne wslayout/HeadlineTextField.as 调整字体大小以适合需要的宽度的 FormattedTextField 类的子类。 com/example/programmingas3/ne wslayout/MultiColumnTextField.as 在两列或多列之间拆分文本的 ActionScript 类。 story.css 为布局定义文本样式的 CSS 文件。327ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 public function onCSSFileLoaded(event:Event):void { this.sheet = new StyleSheet(); this.sheet.parseCSS(loader.data); h1Format = getTextStyle("h1", this.sheet); if (h1Format == null) { h1Format = getDefaultHeadFormat(); } h2Format = getTextStyle("h2", this.sheet); if (h2Format == null) { h2Format = getDefaultHeadFormat(); h2Format.size = 16; } pFormat = getTextStyle("p", this.sheet); if (pFormat == null) { pFormat = getDefaultTextFormat(); pFormat.size = 12; } displayText(); } onCSSFileLoaded() 方法创建一个 StyleSheet 对象并使之分析输入 CSS 数据。素材的主体文本将显示在 MultiColumnTextField 对象中,该对象可以直接使用 StyleSheet 对象。不过,标题字段使用 HeadlineTextField 类,该类 使用 TextFormat 对象进行格式设置。 onCSSFileLoaded() 方法调用两次 getTextStyle() 方法,将 CSS 样式声明转换为 TextFormat 对象,以便与两个 HeadlineTextField 对象中的每个对象配合使用。 328ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 public function getTextStyle(styleName:String, ss:StyleSheet):TextFormat { var format:TextFormat = null; var style:Object = ss.getStyle(styleName); if (style != null) { var colorStr:String = style.color; if (colorStr != null && colorStr.indexOf("#") == 0) { style.color = colorStr.substr(1); } format = new TextFormat(style.fontFamily, style.fontSize, style.color, (style.fontWeight == "bold"), (style.fontStyle == "italic"), (style.textDecoration == "underline"), style.url, style.target, style.textAlign, style.marginLeft, style.marginRight, style.indent, style.leading); if (style.hasOwnProperty("letterSpacing")) { format.letterSpacing = style.letterSpacing; } } return format; } CSS 样式声明和 TextFormat 对象的属性名称和属性值的含义不同。 getTextStyle() 方法可以将 CSS 属性值转换为 TextFormat 对象预期的值。 在页面上排列素材元素 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 StoryLayout 类可以设置标题、副标题和主体文本字段的格式并将这些字段的布局排列为报纸样式。 displayText() 方法一开始 会创建并放置各个字段。329ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 public function displayText():void { headlineTxt = new HeadlineTextField(h1Format); headlineTxt.wordWrap = true; headlineTxt.x = this.paddingLeft; headlineTxt.y = this.paddingTop; headlineTxt.width = this.preferredWidth; this.addChild(headlineTxt); headlineTxt.fitText(this.headline, 1, true); subtitleTxt = new HeadlineTextField(h2Format); subtitleTxt.wordWrap = true; subtitleTxt.x = this.paddingLeft; subtitleTxt.y = headlineTxt.y + headlineTxt.height; subtitleTxt.width = this.preferredWidth; this.addChild(subtitleTxt); subtitleTxt.fitText(this.subtitle, 2, false); storyTxt = new MultiColumnText(this.numColumns, 20, this.preferredWidth, 400, true, this.pFormat); storyTxt.x = this.paddingLeft; storyTxt.y = subtitleTxt.y + subtitleTxt.height + 10; this.addChild(storyTxt); storyTxt.text = this.content; ... 将一个字段的 y 属性设置为等于上一个字段的 y 属性加上其自身高度,这样即可将每个字段放置在上一个字段的下面。由于 HeadlineTextField 对象和 MultiColumnTextField 对象可以更改其高度以适应内容,因此需要进行这种动态位置计算。 更改字体大小以适合字段大小 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在给定要显示内容的宽度 (以像素为单位)和最多行数的情况下, HeadlineTextField 会更改字体大小以使文本适合字段大 小。如果文本短,字体大小很大,就会生成 tabloid 样式的标题。如果文本很长,那么字体大小较小。 下面所示的 HeadlineTextField.fitText() 方法的作用就是调整字体大小: public function fitText(msg:String, maxLines:uint = 1, toUpper:Boolean = false, targetWidth:Number = - 1):uint { this.text = toUpper ? msg.toUpperCase() : msg; if (targetWidth == -1) { targetWidth = this.width; } var pixelsPerChar:Number = targetWidth / msg.length; var pointSize:Number = Math.min(MAX_POINT_SIZE, Math.round(pixelsPerChar * 1.8 * maxLines)); if (pointSize < 6) { // the point size is too small return pointSize; } 330ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 this.changeSize(pointSize); if (this.numLines > maxLines) { return shrinkText(--pointSize, maxLines); } else { return growText(pointSize, maxLines); } } public function growText(pointSize:Number, maxLines:uint = 1):Number { if (pointSize >= MAX_POINT_SIZE) { return pointSize; } this.changeSize(pointSize + 1); if (this.numLines > maxLines) { // set it back to the last size this.changeSize(pointSize); return pointSize; } else { return growText(pointSize + 1, maxLines); } } public function shrinkText(pointSize:Number, maxLines:uint=1):Number { if (pointSize <= MIN_POINT_SIZE) { return pointSize; } this.changeSize(pointSize); if (this.numLines > maxLines) { return shrinkText(pointSize - 1, maxLines); } else { return pointSize; } } HeadlineTextField.fitText() 方法使用简单的递归技术来调整字体大小。首先,该方法推测文本中每个字符的平均像素数,并据 此计算起始点大小。然后,它更改字体大小并检查文本中的文字是否换行,从而产生比最大值更多的文本行。如果文本行过 多,则它会调用 shrinkText() 方法减小字体大小并重试。如果文本行不太多,则它会调用 growText() 方法增大字体大小并重 试。当字体大小再增加一点即会产生过多行时,该过程即会停止。331ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 在多列之间拆分文本 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 MultiColumnTextField 类会在多个 TextField 对象中分布文本,然后将这些对象排列成报纸专栏的样式。 MultiColumnTextField() 构造函数首先创建一个由 TextField 对象构成的数组,每列一个对象,如下所示: for (var i:int = 0; i < cols; i++) { var field:TextField = new TextField(); field.multiline = true; field.autoSize = TextFieldAutoSize.NONE; field.wordWrap = true; field.width = this.colWidth; field.setTextFormat(this.format); this.fieldArray.push(field); this.addChild(field); } 每个 TextField 对象均使用 addChild() 方法添加到该数组中,并添加到显示列表中。 只要 StoryLayout 的 text 属性或 styleSheet 属性发生更改,该对象就会调用 layoutColumns() 方法来重新显示文本。 layoutColumns() 方法会调用 getOptimalHeight() 方法,以计算在给定布局宽度内适合所有文本所需的正确像素高度。 public function getOptimalHeight(str:String):int { if (field.text == "" || field.text == null) { return this.preferredHeight; } else { this.linesPerCol = Math.ceil(field.numLines / this.numColumns); var metrics:TextLineMetrics = field.getLineMetrics(0); this.lineHeight = metrics.height; var prefHeight:int = linesPerCol * this.lineHeight; return prefHeight + 4; } } 首先, getOptimalHeight() 方法计算每列的宽度。然后设置数组中第一个 TextField 对象的宽度和 htmlText 属性。 getOptimalHeight() 方法使用第一个 TextField 对象计算文本中自动换行文本的总行数,并据此确定每列中应有多少行。接下 来,它调用 TextField.getLineMetrics() 方法以检索 TextLineMetrics 对象,该对象包含有关第一行的文本大小的详细信息。 TextLineMetrics.height 属性用像素表示文本行的完整高度,包括上缘、下缘和前导。 MultiColumnTextField 对象的最佳高 度即为行高度乘以每列行数再加上 4 (TextField 对象顶部边框和底部边框各 2 个像素)。 以下是完整 layoutColumns() 方法的代码:332ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 public function layoutColumns():void { if (this._text == "" || this._text == null) { return; } var field:TextField = fieldArray[0] as TextField; field.text = this._text; field.setTextFormat(this.format); this.preferredHeight = this.getOptimalHeight(field); var remainder:String = this._text; var fieldText:String = ""; var lastLineEndedPara:Boolean = true; var indent:Number = this.format.indent as Number; for (var i:int = 0; i < fieldArray.length; i++) { field = this.fieldArray[i] as TextField; field.height = this.preferredHeight; field.text = remainder; field.setTextFormat(this.format); var lineLen:int; if (indent > 0 && !lastLineEndedPara && field.numLines > 0) { lineLen = field.getLineLength(0); if (lineLen > 0) { field.setTextFormat(this.firstLineFormat, 0, lineLen); } } field.x = i * (colWidth + gutter); field.y = 0; remainder = ""; fieldText = ""; var linesRemaining:int = field.numLines; var linesVisible:int = Math.min(this.linesPerCol, linesRemaining); for (var j:int = 0; j < linesRemaining; j++) { if (j < linesVisible) { fieldText += field.getLineText(j); } else { remainder +=field.getLineText(j); } } field.text = fieldText; field.setTextFormat(this.format); 333ACTIONSCRIPT 3.0 开发人员指南 使用 TextField 类 上次更新 2014/12/1 if (indent > 0 && !lastLineEndedPara) { lineLen = field.getLineLength(0); if (lineLen > 0) { field.setTextFormat(this.firstLineFormat, 0, lineLen); } } var lastLine:String = field.getLineText(field.numLines - 1); var lastCharCode:Number = lastLine.charCodeAt(lastLine.length - 1); if (lastCharCode == 10 || lastCharCode == 13) { lastLineEndedPara = true; } else { lastLineEndedPara = false; } if ((this.format.align == TextFormatAlign.JUSTIFY) && (i < fieldArray.length - 1)) { if (!lastLineEndedPara) { justifyLastLine(field, lastLine); } } } } 通过调用 getOptimalHeight() 方法设置 preferredHeight 属性后,layoutColumns() 方法会循环访问各个 TextField 对象,将每个 对象的高度设置为 preferredHeight 值。然后, layoutColumns() 方法会为每个字段分布刚好足够的文本行,以使每个字段中都 不会发生滚动,并且每个连续字段中的文本均会从前一个字段的文本结束处开始。如果文本对齐样式已设置为 “justify”,则会 调用 justifyLastLine() 方法以对齐字段中最后一行文本。否则,最后一行将被视为段落结束行,而不予对齐。334 上次更新 2014/12/1 第 22 章 : 使用 Flash 文本引擎 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 从 Flash Player 10 和 Adobe® AIR™1.5 开始提供的 Adobe® Flash® 文本引擎 (FTE) 为文本度量、格式设置和双向文本的复杂 控制提供了底层支持。它提供了改进的文本流和增强的语言支持。尽管可以使用 FTE 创建和管理简单的文本元素,但设计 FTE 的主要目的是为开发人员创建文本处理组件提供基础。因此, Flash 文本引擎采用了更高级的编程技术。要显示简单文本 元素,请参阅第 313 页的 “ 使用 TextField 类 ”。 Text Layout Framework 包括一个基于 FTE 的文本处理组件,提供了一种比较容易的使用其高级功能的方法。Text Layout Framework 是完全内置于 ActionScript 3.0 的可扩展库。您可以使用现有的 TLF 组件,或者使用框架构建您自己的文本组 件。有关更多信息,请参阅第 360 页的 “ 使用 Text Layout Framework”。 更多帮助主题 flash.text.engine 包 创建和显示文本 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 组成 Flash 文本引擎的类可用于创建文本、设置文本格式以及控制文本。下面的类是通过 Flash 文本引擎创建和显示文本时所 用的基本构造块: • TextElement/GraphicElement/GroupElement:包含 TextBlock 实例的内容 • ElementFormat:指定 TextBlock 实例内容的格式设置属性 • TextBlock:用于构建文本段落的工厂 • TextLine:依据 TextBlock 创建的文本行 要显示文本,可从字符串创建一个 TextElement 对象,使用 ElementFormat 对象指定格式设置特征。将 TextElement 分配 给 TextBlock 对象的 content 属性。通过调用 TextBlock.createTextLine() 方法创建将要显示的文本行。createTextLine() 方法返 回一个 TextLine 对象,该对象包含的字符串长度与将适合的指定宽度相同。重复调用此方法,直到整个字符串格式设置为行。 当没有更多的行要创建时, TextBlock 对象的 textLineCreationResult 属性将分配值:TextLineCreationResult.COMPLETE。 要显示行,请将它们添加到显示列表 (x 和 y 的位置值要适当)。 例如,以下代码使用这些 FTE 类显示 “Hello World! This is Flash Text Engine!”,显示时使用默认的格式和字体值。在此 简单示例中,仅创建了一行文本。335ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 package { import flash.text.engine.*; import flash.display.Sprite; public class HelloWorldExample extends Sprite { public function HelloWorldExample() { var str = "Hello World! This is Flash Text Engine!"; var format:ElementFormat = new ElementFormat(); var textElement:TextElement = new TextElement(str, format); var textBlock:TextBlock = new TextBlock(); textBlock.content = textElement; var textLine1:TextLine = textBlock.createTextLine(null, 300); addChild(textLine1); textLine1.x = 30; textLine1.y = 30; } } } createTextLine() 的参数指定新行从哪一行开始,以及新行的宽度 (单位为像素)。新行通常从前一行开始,但如果新行是第一 行,则为 null。 添加 GraphicElement 和 GroupElement 对象 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 可以将 GraphicElement 对象分配给 TextBlock 对象以显示图像或图形元素。直接从图形或图像创建一个 GraphicElement 类的实例,然后将该实例分配给 TextBlock.content 属性。按照常规的方法调用 TextBlock.createTextline() 来创建文本行。下面 的示例创建两个文本行,一个用 GraphicElement 对象创建,另一个用 TextElement 对象创建。 package { import flash.text.engine.*; import flash.display.Sprite; import flash.display.Shape; import flash.display.Graphics; public class GraphicElementExample extends Sprite { public function GraphicElementExample() { var str:String = "Beware of Dog!"; var triangle:Shape = new Shape(); triangle.graphics.beginFill(0xFF0000, 1); triangle.graphics.lineStyle(3); triangle.graphics.moveTo(30, 0); triangle.graphics.lineTo(60, 50); triangle.graphics.lineTo(0, 50); triangle.graphics.lineTo(30, 0); triangle.graphics.endFill(); var format:ElementFormat = new ElementFormat(); 336ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 format.fontSize = 20; var graphicElement:GraphicElement = new GraphicElement(triangle, triangle.width, triangle.height, format); var textBlock:TextBlock = new TextBlock(); textBlock.content = graphicElement; var textLine1:TextLine = textBlock.createTextLine(null, triangle.width); textLine1.x = 50; textLine1.y = 110; addChild(textLine1); var textElement:TextElement = new TextElement(str, format); textBlock.content = textElement; var textLine2 = textBlock.createTextLine(null, 300); addChild(textLine2); textLine2.x = textLine1.x - 30; textLine2.y = textLine1.y + 15; } } } 您可以创建 GroupElement 对象,以创建一组 TextElement 对象、 GraphicElement 对象和其他 GroupElement 对象。 GroupElement 可以分配给 TextBlock 对象的 content 属性。GroupElement() 构造函数的参数是一个 Vector,它指向构成组 的文本、图形以及组元素。下面的示例将两个图形元素和一个文本元素组成一组,然后将它们作为一个单元分配给某个文本 块。 package { import flash.text.engine.*; import flash.display.Sprite; import flash.display.Shape; import flash.display.Graphics; public class GroupElementExample extends Sprite { public function GroupElementExample() { var str:String = "Beware of Alligators!"; var triangle1:Shape = new Shape(); triangle1.graphics.beginFill(0xFF0000, 1); triangle1.graphics.lineStyle(3); triangle1.graphics.moveTo(30, 0); triangle1.graphics.lineTo(60, 50); triangle1.graphics.lineTo(0, 50); triangle1.graphics.lineTo(30, 0); triangle1.graphics.endFill(); var triangle2:Shape = new Shape(); triangle2.graphics.beginFill(0xFF0000, 1); triangle2.graphics.lineStyle(3); triangle2.graphics.moveTo(30, 0); triangle2.graphics.lineTo(60, 50); triangle2.graphics.lineTo(0, 50); triangle2.graphics.lineTo(30, 0); triangle2.graphics.endFill(); 337ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 var format:ElementFormat = new ElementFormat(); format.fontSize = 20; var graphicElement1:GraphicElement = new GraphicElement(triangle1, triangle1.width, triangle1.height, format); var textElement:TextElement = new TextElement(str, format); var graphicElement2:GraphicElement = new GraphicElement(triangle2, triangle2.width, triangle2.height, format); var groupVector:Vector. = new Vector.(); groupVector.push(graphicElement1, textElement, graphicElement2); var groupElement = new GroupElement(groupVector); var textBlock:TextBlock = new TextBlock(); textBlock.content = groupElement; var textLine:TextLine = textBlock.createTextLine(null, 800); addChild(textLine); textLine.x = 100; textLine.y = 200; } } } 替换文本 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 您可以调用 TextElement.replaceText() 来替换您分配给 TextBlock.content 属性的 TextElement 中的文本,从而替换 TextBlock 实例中的文本。 以下示例首先使用 replaceText() 在行首插入文本,然后在行尾追加文本,最后在行的中间位置替换文本。338ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 package { import flash.text.engine.*; import flash.display.Sprite; public class ReplaceTextExample extends Sprite { public function ReplaceTextExample() { var str:String = "Lorem ipsum dolor sit amet"; var fontDescription:FontDescription = new FontDescription("Arial"); var format:ElementFormat = new ElementFormat(fontDescription); format.fontSize = 14; var textElement:TextElement = new TextElement(str, format); var textBlock:TextBlock = new TextBlock(); textBlock.content = textElement; createLine(textBlock, 10); textElement.replaceText(0, 0, "A text fragment: "); createLine(textBlock, 30); textElement.replaceText(43, 43, "..."); createLine(textBlock, 50); textElement.replaceText(23, 28, "(ipsum)"); createLine(textBlock, 70); } function createLine(textBlock:TextBlock, y:Number):void { var textLine:TextLine = textBlock.createTextLine(null, 300); textLine.x = 10; textLine.y = y; addChild(textLine); } } } 该 replaceText() 方法将 beginIndex 和 endIndex 参数指定的文本替换为 newText 参数指定的文本。如果 beginIndex 和 endIndex 参数的值相同,replaceText() 将在相应的位置插入指定的文本。否则,将用新文本替换 beginIndex 和 endIndex 所指定的字符。 处理 FTE 中的事件 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 您可以将事件侦听器添加到 TextLine 实例中,就像添加到其他显示对象一样。例如,您可以检测用户何时将鼠标移动到某个 文本行的上方,或者用户何时单击此行。下面的示例检测这两种事件。如果将鼠标移动到此行的上方,光标将变为按钮光标, 并且如果单击此行,此行将会变色。339ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 package { import flash.text.engine.*; import flash.ui.Mouse; import flash.display.Sprite import flash.events.MouseEvent; import flash.events.EventDispatcher; public class EventHandlerExample extends Sprite { var textBlock:TextBlock = new TextBlock(); public function EventHandlerExample():void { var str:String = "I'll change color if you click me."; var fontDescription:FontDescription = new FontDescription("Arial"); var format:ElementFormat = new ElementFormat(fontDescription, 18); var textElement = new TextElement(str, format); textBlock.content = textElement; createLine(textBlock); } private function createLine(textBlock:TextBlock):void { var textLine:TextLine = textBlock.createTextLine(null, 500); textLine.x = 30; textLine.y = 30; addChild(textLine); textLine.addEventListener("mouseOut", mouseOutHandler); textLine.addEventListener("mouseOver", mouseOverHandler); textLine.addEventListener("click", clickHandler); } private function mouseOverHandler(event:MouseEvent):void { Mouse.cursor = "button"; } private function mouseOutHandler(event:MouseEvent):void { Mouse.cursor = "arrow"; } function clickHandler(event:MouseEvent):void { if(textBlock.firstLine) removeChild(textBlock.firstLine); var newFormat:ElementFormat = textBlock.content.elementFormat.clone(); 340ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 switch(newFormat.color) { case 0x000000: newFormat.color = 0xFF0000; break; case 0xFF0000: newFormat.color = 0x00FF00; break; case 0x00FF00: newFormat.color = 0x0000FF; break; case 0x0000FF: newFormat.color = 0x000000; break; } textBlock.content.elementFormat = newFormat; createLine(textBlock); } } } 镜像事件 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 另外,还可将文本块或文本块局部的事件映射到事件调度程序。首先,创建一个 EventDispatcher 实例,然后将其分配给 TextElement 实例的 eventMirror 属性。如果文本块由一个文本元素组成,那么文本引擎将映射整个文本块的事件。如果文本 块由多个文本元素组成,那么文本引擎只映射设置了 eventMirror 属性的 TextElement 实例的事件。下面示例中的文本由三个 元素组成:单词 “Click”、单词 “here” 以及字符串 “to see me in italic”。此示例将事件调度程序分配给第二个文本元素,即单 词 “here”,然后添加事件侦听器 clickHandler() 方法。该 clickHandler() 方法将文本更改为斜体。另外,它还将第三个文本元素 的内容替换为 “Click here to see me in normal font!”。 package { import flash.text.engine.*; import flash.ui.Mouse; import flash.display.Sprite; import flash.events.MouseEvent; import flash.events.EventDispatcher; public class EventMirrorExample extends Sprite { var fontDescription:FontDescription = new FontDescription("Helvetica", "bold"); var format:ElementFormat = new ElementFormat(fontDescription, 18); var textElement1 = new TextElement("Click ", format); var textElement2 = new TextElement("here ", format); var textElement3 = new TextElement("to see me in italic! ", format); var textBlock:TextBlock = new TextBlock(); public function EventMirrorExample() { var myEvent:EventDispatcher = new EventDispatcher(); myEvent.addEventListener("click", clickHandler); myEvent.addEventListener("mouseOut", mouseOutHandler); myEvent.addEventListener("mouseOver", mouseOverHandler); textElement2.eventMirror=myEvent; var groupVector:Vector. = new Vector.; 341ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 groupVector.push(textElement1, textElement2, textElement3); var groupElement:GroupElement = new GroupElement(groupVector); textBlock.content = groupElement; createLines(textBlock); } private function clickHandler(event:MouseEvent):void { var newFont:FontDescription = new FontDescription(); newFont.fontWeight = "bold"; var newFormat:ElementFormat = new ElementFormat(); newFormat.fontSize = 18; if(textElement3.text == "to see me in italic! ") { newFont.fontPosture = FontPosture.ITALIC; textElement3.replaceText(0,21, "to see me in normal font! "); } else { newFont.fontPosture = FontPosture.NORMAL; textElement3.replaceText(0, 26, "to see me in italic! "); } newFormat.fontDescription = newFont; textElement1.elementFormat = newFormat; textElement2.elementFormat = newFormat; textElement3.elementFormat = newFormat; createLines(textBlock); } private function mouseOverHandler(event:MouseEvent):void { Mouse.cursor = "button"; } private function mouseOutHandler(event:MouseEvent):void { Mouse.cursor = "arrow"; } private function createLines(textBlock:TextBlock):void { if(textBlock.firstLine) removeChild (textBlock.firstLine); var textLine:TextLine = textBlock.createTextLine (null, 300); textLine.x = 15; textLine.y = 20; addChild (textLine); } } } mouseOverHandler() 和 mouseOutHandler() 函数在光标位于单词 “here” 上方时将光标设置为按钮光标,在光标不在 “here” 上方时将光标恢复为箭头。342ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 设置文本格式 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 TextBlock 对象是用于创建文本行的工厂。 TextBlock 的内容是通过 TextElement 对象分配的。 ElementFormat 对象负责处理文 本的格式设置。 ElementFormat 类定义基线对齐、字距调整、间距、文本旋转以及字体大小、颜色和大小写等属性。它还包 含 FontDescription,相关内容在第 345 页的 “ 使用字体 ” 中详细介绍。 使用 ElementFormat 对象 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 ElementFormat 对象的构造函数可以接受一长串可选参数中的任何一个参数,包括 FontDescription。也可以在构造函数之外设 置这些属性。下面的示例演示了在定义和显示简单文本行时各个对象的关系: package { import flash.display.Sprite; import flash.text.*; public class ElementFormatExample extends Sprite { private var tb:TextBlock = new TextBlock(); private var te:TextElement; private var ef:ElementFormat; private var fd:FontDescription = new FontDescription(); private var str:String; private var tl:TextLine; public function ElementFormatExample() { fd.fontName = "Garamond"; ef = new ElementFormat(fd); ef.fontSize = 30; ef.color = 0xFF0000; str = "This is flash text"; te = new TextElement(str, ef); tb.content = te; tl = tb.createTextLine(null,600); addChild(tl); } } } 字体颜色和透明度 (alpha) Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 ElementFormat 对象的 color 属性设置字体颜色。该值是一个表示 RGB 颜色分量的整数;例如, 0xFF0000 表示红色, 0x00FF00 表示绿色。默认值是黑色 (0x000000)。 alpha 属性设置元素 (TextElement 和 GraphicElement)的 alpha 透明度值。值范围介于 0 (完全透明)到 1 (完全不透明, 默认值)之间。 alpha 为 0 的元素不可见,但仍为活动元素。此值乘以继承的 alpha 值,因而元素更为透明。343ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 var ef:ElementFormat = new ElementFormat(); ef.alpha = 0.8; ef.color = 0x999999; 基线对齐和移位 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 行中最大文本的字体和大小决定了行的主要基线。可通过设置 TextBlock.baselineFontDescription 和 TextBlock.baselineFontSize 来覆盖这些值。可以将主要基线与文本内多个基线中的一个对齐。这些基线包括上缘线和下缘线或表意字顶部、中心或者底 部。 A. 上缘 B. 基线 C. 下缘 D. x 高度 在 ElementFormat 对象中,三个属性决定了基线和对齐特征。alignmentBaseline 属性设置 TextElement 或 GraphicElement 的主 基线。此基线是元素的 “ 贴紧 ” 线,所有文本的主要基线均对齐此位置。 dominantBaseline 属性指定要使用各个元素基线中的哪个基线,这决定了元素在行中的垂直位置。默认值为 TextBaseline.ROMAN,但也可以设置为使用 IDEOGRAPHIC_TOP 基线或 IDEOGRAPHIC_BOTTOM 基线作为主要基线。 baselineShift 属性将基线沿 Y 轴移动一定像素数的距离。在正常 (非旋转)文本中,正数值使基线下移,负数值使基线上移。 印刷大小写 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 ElementFormat 的 TypographicCase 属性指定文本大小写,如大写、小写或小型大写字母。 var ef_Upper:ElementFormat = new ElementFormat(); ef_Upper.typographicCase = TypographicCase.UPPERCASE; var ef_SmallCaps:ElementFormat = new ElementFormat(); ef_SmallCaps.typographicCase = TypographicCase.SMALL_CAPS; 旋转文本 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 可按 90 度的增量旋转文本块或文本段中的字形。 TextRotation 类定义了以下常量,用于设置文本块和字型旋转: 常量 值 说明 AUTO “auto” 指定 90 度逆时针旋转。通常用于垂直的亚洲文字,以仅旋转需要旋转的字型。 ROTATE_0 “rotate_0” 指定不进行旋转。 D A CB344ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 若要旋转文本块中的多行文本,请在调用 TextBlock.createTextLine() 方法创建文本行之前设置 TextBlock.lineRotation 属性。 若要旋转文本块或文本段中的字型,请将 ElementFormat.textRotation 属性设置为字型要旋转的度数。字型是构成字符的形状, 或者是由多个字型组成的一部分字符。例如,字母 “a” 和 “i” 上的点都是字形。 在某些亚洲语言中会涉及旋转字型。在这些语言中,需要将行旋转到垂直方向,但不旋转行中的字符。有关旋转亚洲文字的详 细信息,请参阅第 348 页的 “ 对齐东亚文本 ”。 下面的示例同时旋转文本块以及其中的字型,就像处理亚洲文字那样。该示例也使用日文字体: package { import flash.display.Sprite; import flash.text.*; public class RotationExample extends Sprite { private var tb:TextBlock = new TextBlock(); private var te:TextElement; private var ef:ElementFormat; private var fd:FontDescription = new FontDescription(); private var str:String; private var tl:TextLine; public function RotationExample() { fd.fontName = "MS Mincho"; ef = new ElementFormat(fd); ef.textRotation = TextRotation.AUTO; str = "This is rotated Japanese text"; te = new TextElement(str, ef); tb.lineRotation = TextRotation.ROTATE_90; tb.content = te; tl = tb.createTextLine(null,600); addChild(tl); } } } 锁定和克隆 ElementFormat Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 当 ElementFormat 对象分配给任何类型的 ContentElement 时,其 locked 属性自动设置为 true。试图修改锁定的 ElementFormat 对象将会引发 IllegalOperationError。最佳做法是先完全定义这类对象,然后将其分配给 TextElement 实例。 如果要修改某个现有 ElementFormat 实例,请首先检查其 locked 属性。如果该属性为 true,请使用 clone() 方法创建对象的未 锁定副本。此未锁定对象的属性可以更改,然后可以将其指派给 TextElement 实例。依据此对象创建的所有新行均具有新的格 式设置。前面依据此对象创建并使用旧格式的行保持不变。 ROTATE_180 “rotate_180” 指定 180 度旋转。 ROTATE_270 “rotate_270” 指定 270 度旋转。 ROTATE_90 “rotate_90” 指定 90 度顺时针旋转。 常量 值 说明345ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 package { import flash.display.Sprite; import flash.text.*; public class ElementFormatCloneExample extends Sprite { private var tb:TextBlock = new TextBlock(); private var te:TextElement; private var ef1:ElementFormat; private var ef2:ElementFormat; private var fd:FontDescription = new FontDescription(); public function ElementFormatCloneExample() { fd.fontName = "Garamond"; ef1 = new ElementFormat(fd); ef1.fontSize = 24; var str:String = "This is flash text"; te = new TextElement(str, ef); tb.content = te; var tx1:TextLine = tb.createTextLine(null,600); addChild(tx1); ef2 = (ef1.locked) ? ef1.clone() : ef1; ef2.fontSize = 32; tb.content.elementFormat = ef2; var tx2:TextLine = tb.createTextLine(null,600); addChild(tx2); } } } 使用字体 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 FontDescription 对象与 ElementFormat 配合使用可以标识字型,以及定义其部分特征。这些特征包括字体名称、粗细、形态、 呈示以及如何查找字体 (设备字体与嵌入字体)。 注: FTE 不支持 Type 1 字体或 Type 3、 ATC、 sfnt 换行 CID 或 Naked CID 等位图字体。 定义字体特征 (FontDescription 对象) Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 FontDescription 对象的 fontName 属性可以是单个名称,也可以是逗号分隔的名称列表。例如,在 “Arial, Helvetica, _sans” 等列表中,文本引擎先查找 “Arial”,然后查找 “Helvetica”,如果这两种字体都找不到,则最后查找 “_sans”。在字体名称集 中有三个通用设备字体名称:“_sans”、 “_serif” 和 “_typewriter”。这些名称根据播放系统映射到具体的设备字体。在使用设 备字体的所有字体说明中指定此类默认名称是一种很好的做法。如果没有指定任何 fontName,则默认使用 “_serif”。 fontPosture 属性可设置为默认值 (FontPosture.NORMAL),也可设置为斜体 (FontPosture.ITALIC)。 fontWeight 属性可设置为 默认值 (FontWeight.NORMAL),也可设置为粗体 (FontWeight.BOLD)。346ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 var fd1:FontDescription = new FontDescription(); fd1.fontName = "Arial, Helvetica, _sans"; fd1.fontPosture = FontPosture.NORMAL; fd1.fontWeight = FontWeight.BOLD; 嵌入字体和设备字体 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 FontDescription 对象的 fontLookup 属性指定文本引擎是查找设备字体还是嵌入字体来呈现文本。如果指定设备字体 (FontLookup.DEVICE),则运行时将在播放系统中查找该字体。如果指定嵌入字体 (FontLookup.EMBEDDED_CFF),运行时 将在 SWF 文件中查找具有指定名称的嵌入字体。只有嵌入的 CFF (压缩字体格式)字体才可使用此项设置。如果没有找到指 定的字体,则会使用后备设备字体。 使用设备字体,得到的 SWF 文件较小。嵌入字体提供了更高的跨平台保真度。 var fd1:FontDescription = new FontDescription(); fd1.fontLookup = FontLookup.EMBEDDED_CFF; fd1.fontName = "Garamond, _serif"; 呈现模式和提示 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 从 Flash Player 10 和 Adobe AIR 1.5 开始提供 CFF (压缩字体格式)呈示。以此方式呈示字体能使文本更加清晰可辨,并 为小字号的字体提供更高品质的显示效果。此项设置只适用于嵌入字体。对于 renderingMode 属性,FontDescription 默认设为 此项设置 (RenderingMode.CFF)。可以将此属性设置为 RenderingMode.NORMAL,从而与 Flash Player 7 或更低版本所使用 的呈示类型保持一致。 选择 CFF 呈示之后,将由另一个属性 cffHinting 控制字体水平线适合子像素网格的方式。默认值 CFFHinting.HORIZONTAL_STEM 使用 CFF 提示。将此属性设置为 CFFHinting.NONE 将会消除提示,对于动画或大字号应 当如此设置。 var fd1:FontDescription = new FontDescription(); fd1.renderingMode = RenderingMode.CFF; fd1.cffHinting = CFFHinting.HORIZONTAL_STEM; 锁定和克隆 FontDescription Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 当 FontDescription 对象分配给 ElementFormat 时,其 locked 属性自动设置为 true。试图修改锁定的 FontDescription 对象将会 引发 IllegalOperationError。最佳做法是先完全定义这类对象,然后将其分配给 ElementFormat。 如果要修改某个现有 FontDescription,请首先检查其 locked 属性。如果该属性为 true,请使用 clone() 方法创建对象的未锁定 副本。此未锁定对象的属性可以更改,然后可以将其指派给 ElementFormat。根据此 TextElement 创建的所有新行均具有新的 格式设置。以前根据这个对象创建的行保持不变。347ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 package { import flash.display.Sprite; import flash.text.*; public class FontDescriptionCloneExample extends Sprite { private var tb:TextBlock = new TextBlock(); private var te:TextElement; private var ef1:ElementFormat; private var ef2:ElementFormat; private var fd1:FontDescription = new FontDescription(); private var fd2:FontDescription; public function FontDescriptionCloneExample() { fd1.fontName = "Garamond"; ef1 = new ElementFormat(fd); var str:String = "This is flash text"; te = new TextElement(str, ef); tb.content = te; var tx1:TextLine = tb.createTextLine(null,600); addChild(tx1); fd2 = (fd1.locked) ? fd1.clone() : fd1; fd2.fontName = "Arial"; ef2 = (ef1.locked) ? ef1.clone() : ef1; ef2.fontDescription = fd2; tb.content.elementFormat = ef2; var tx2:TextLine = tb.createTextLine(null,600); addChild(tx2); } } } 控制文本 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 FTE 提供了一组新的文本格式控件,用以处理对齐和字符间距 (字距调整和间距)。还有一些属性可用于控制各行断开方式以 及在行中设置 Tab 停靠位。 对齐文本 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 通过调整单词之间 (有的时候是字母之间)的间距,对齐文本能让段落中各行的长度相等。其效果是文本两端对齐,而单词和 字母之间的间距发生变化。报刊杂志中的文本栏通常是对齐的。 SpaceJustifier 类中的 lineJustfication 属性可用于控制文本块中各行的对齐情况。 LineJustification 类定义了可用于指定对齐 选项的常量:ALL_BUT_LAST 对齐除文本最后一行之外的所有各行; ALL_INCLUDING_LAST 对齐所有文本,包括最后一行 ; UNJUSTIFIED 是默认值,保持文本的不对齐状态。 若要对齐文本,请将 lineJustification 属性设置为 SpaceJustifier 类的实例,并将该实例指派给 TextBlock 实例的 textJustifier 属性。下面的示例创建一个段落。在此段落中,除最后一行文本之外,所有各行均对齐。348ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 package { import flash.text.engine.*; import flash.display.Sprite; public class JustifyExample extends Sprite { public function JustifyExample() { var str:String = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " + "enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + "aliquip ex ea commodo consequat."; var format:ElementFormat = new ElementFormat(); var textElement:TextElement=new TextElement(str,format); var spaceJustifier:SpaceJustifier=new SpaceJustifier("en",LineJustification.ALL_BUT_LAST); var textBlock:TextBlock = new TextBlock(); textBlock.content=textElement; textBlock.textJustifier=spaceJustifier; createLines(textBlock); } private function createLines(textBlock:TextBlock):void { var yPos=20; var textLine:TextLine=textBlock.createTextLine(null,150); while (textLine) { addChild(textLine); textLine.x=15; yPos+=textLine.textHeight+2; textLine.y=yPos; textLine=textBlock.createTextLine(textLine,150); } } } } 若要更改字母以及单词之间的间距,请将 SpaceJustifier.letterspacing 属性设置为 true。应用字母间距调整功能可以减少单词间 出现不美观间隙 (简单对齐有时会出现这种情况)的几率。 对齐东亚文本 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 对齐东亚文字时,需要额外注意一些事项。东亚文字可能是从上至下书写,且某些字符 (称为避头尾)不能出现在行首或行 尾。 JustificationStyle 类定义了以下常量,这些常量指定了用于处理这些字符的选项。 PRIORITIZE_LEAST_ADJUSTMENT 通过扩展行或压缩行进行对齐,具体采用哪种方式取决于能否产生最理想的效果。 PUSH_IN_KINSOKU 通过行尾压缩避头尾 或扩展行 (如果没有避头尾或该空间不足)进行对齐。 PUSH_OUT_ONLY 通过扩展行进行对齐。若要创建垂直的亚洲文本块,请将 TextBlock.lineRotation 属性设置为 TextRotation.ROTATE_90,并将 ElementFormat.textRotation 属性设置为 TextRotation.AUTO (默认值)。将 textRotation 属 性设置为 AUTO 将使文本中的字型保持垂直,而不是在整行发生旋转的时候侧向旋转。根据字形的 Unicode 属性, AUTO 设 置仅将全宽字形和宽字形逆时针旋转 90°。下面的示例显示垂直的日文文本块,并使用 PUSH_IN_KINSOKU 选项使其对齐。349ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 package { import flash.text.engine.*; import flash.display.Stage; import flash.display.Sprite; import flash.system.Capabilities; public class EastAsianJustifyExample extends Sprite { public function EastAsianJustifyExample() { var Japanese_txt:String = String.fromCharCode( 0x5185, 0x95A3, 0x5E9C, 0x304C, 0x300C, 0x653F, 0x5E9C, 0x30A4, 0x30F3, 0x30BF, 0x30FC, 0x30CD, 0x30C3, 0x30C8, 0x30C6, 0x30EC, 0x30D3, 0x300D, 0x306E, 0x52D5, 0x753B, 0x914D, 0x4FE1, 0x5411, 0x3051, 0x306B, 0x30A2, 0x30C9, 0x30D3, 0x30B7, 0x30B9, 0x30C6, 0x30E0, 0x30BA, 0x793E, 0x306E) var textBlock:TextBlock = new TextBlock(); var font:FontDescription = new FontDescription(); var format:ElementFormat = new ElementFormat(); format.fontSize = 12; format.color = 0xCC0000; format.textRotation = TextRotation.AUTO; textBlock.baselineZero = TextBaseline.IDEOGRAPHIC_CENTER; var eastAsianJustifier:EastAsianJustifier = new EastAsianJustifier("ja", LineJustification.ALL_BUT_LAST); eastAsianJustifier.justificationStyle = JustificationStyle.PUSH_IN_KINSOKU; textBlock.textJustifier = eastAsianJustifier; textBlock.lineRotation = TextRotation.ROTATE_90; var linePosition:Number = this.stage.stageWidth - 75; if (Capabilities.os.search("Mac OS") > -1) // set fontName: Kozuka Mincho Pro R font.fontName = String.fromCharCode(0x5C0F, 0x585A, 0x660E, 0x671D) + " Pro R"; else font.fontName = "Kozuka Mincho Pro R"; textBlock.content = new TextElement(Japanese_txt, format); var previousLine:TextLine = null; while (true) { var textLine:TextLine = textBlock.createTextLine(previousLine, 200); if (textLine == null) break; textLine.y = 20; textLine.x = linePosition; linePosition -= 25; addChild(textLine); previousLine = textLine; } } } } 字距调整和间距 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 字距调整和间距影响文本块中相邻两个字符之间的距离。字距调整控制字符对如何组合在一起,例如字符对 “WA” 或 “Va”。 字距调整在 ElementFormat 对象中设置。字距调整默认为启用 (Kerning.ON)。它可以设置为 OFF 或 AUTO,在此情形中,只 有两个字符都不是日本汉字、平假名和片假名时,才在它们之间应用字距调整。350ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 间距处理在文本块中的所有字符之间增加或减少一定数量的像素,并且也是在 ElementFormat 对象中进行设置。嵌入字体和设 备字体均可使用间距处理。 FTE 支持两种间距属性:trackingLeft,增加 / 减少字符左侧的像素;以及 trackingRight,增加 / 减 少字符右侧的像素。如果使用间距,那么每个字符对的字距调整值将会加上或减去间距值。 A. Kerning.OFF B. TrackingRight=5, Kerning.OFF C. TrackingRight=-5, Kerning.OFF D. Kerning.ON E. TrackingRight=-5, Kerning.ON F. TrackingRight=-5, Kerning.ON var ef1:ElementFormat = new ElementFormat(); ef1.kerning = Kerning.OFF; var ef2:ElementFormat = new ElementFormat(); ef2.kerning = Kerning.ON; ef2.trackingLeft = 0.8; ef2.trackingRight = 0.8; var ef3:ElementFormat = new ElementFormat(); ef3.trackingRight = -0.2; 换行文本的换行符 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 ElementFormat 对象的 breakOpportunity 属性确定在换行文本分成多行时,哪些字符可用于断行。默认值 BreakOpportunity.AUTO 使用标准 Unicode 属性,例如在不同单词之间断行,以及在连字符的位置断行。如果使用 BreakOpportunity.ALL,那么在任何一个字符均可断行,这有助于制造某些效果 (例如沿某个路径排列文本)。 var ef:ElementFormat = new ElementFormat(); ef.breakOpportunity = BreakOpportunity.ALL; Tab 停靠位 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 若要在文本块中设置 Tab 停靠位,请通过创建 TabStop 类的实例来定义 Tab 停靠位。TabStop() 构造函数的参数指定文本如何 与 Tab 停靠位对齐。这些参数指定 Tab 停靠位的位置,以及对于十进制数对齐,指定要在哪个值对齐 (表示为字符串)。通 常,该值是小数点,但也可以是逗号、美元符号或日元或欧元符号等。下面的代码行创建一个名为 tab1 的 Tab 停靠位。 var tab1:TabStop = new TabStop(TabAlignment.DECIMAL, 50, "."); 为一个文本块创建 Tab 停靠位之后,请将这些停靠位分配给 TextBlock 实例的 tabStops 属性。由于 tabStops 属性需要一个 Vector,首先创建一个 Vector,然后将 Tab 停靠位添加到此 Vector 中。此 Vector 允许您将一组 Tab 停靠位分配给文本块。 下面的示例创建一个 Vector 实例,并将一组 TabStop 对象添加到其中。然后,代码将这些 Tab 停靠位分配给 TextBlock 实例的 tabStops 属性。 VAY VAY VAY VAY VAY VAY A B C D E F351ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 var tabStops:Vector. = new Vector.(); tabStops.push(tab1, tab2, tab3, tab4); textBlock.tabStops = tabStops 有关矢量的详细信息,请参阅第 21 页的 “ 使用数组 ”。 下面的示例演示每个 TabStop 对齐选项的效果。 package { import flash.text.engine.*; import flash.display.Sprite; public class TabStopExample extends Sprite { public function TabStopExample() { var format:ElementFormat = new ElementFormat(); format.fontDescription = new FontDescription("Arial"); format.fontSize = 16; var tabStops:Vector. = new Vector.(); tabStops.push( new TabStop(TabAlignment.START, 20), new TabStop(TabAlignment.CENTER, 140), new TabStop(TabAlignment.DECIMAL, 260, "."), new TabStop(TabAlignment.END, 380)); var textBlock:TextBlock = new TextBlock(); textBlock.content = new TextElement( "\tt1\tt2\tt3\tt4\n" + "\tThis line aligns on 1st tab\n" + "\t\t\t\tThis is the end\n" + "\tThe following fragment centers on the 2nd tab:\t\t\n" + "\t\tit's on me\t\t\n" + "\tThe following amounts align on the decimal point:\n" + "\t\t\t45.00\t\n" + "\t\t\t75,320.00\t\n" + "\t\t\t6,950.00\t\n" + "\t\t\t7.01\t\n", format); textBlock.tabStops = tabStops; var yPosition:Number = 60; var previousTextLine:TextLine = null; var textLine:TextLine; var i:int; for (i = 0; i < 10; i++) { textLine = textBlock.createTextLine(previousTextLine, 1000, 0); textLine.x = 20; textLine.y = yPosition; addChild(textLine); yPosition += 25; previousTextLine = textLine; } } } }352ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 Flash 文本引擎示例:新闻版面布局 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 此编程示例演示在为简单的新闻页面布局时,如何使用 Flash 文本引擎。该页包含大标题、副标题和包含多列的正文部分。 首先,创建一个 FLA 文件,并将以下代码附加到默认图层的第 2 帧: import com.example.programmingas3.newslayout.StoryLayout ; // frame sc ript - create a 3-columned arti cle layout var story:StoryLayout = new StoryLayout(720, 500, 3, 10); story.x = 20; story.y = 80; addChild(story); stop(); StoryLayout.as 是本示例的控制器脚本。它设置内容,从外部样式表读取样式信息,将这些样式分配给 ElementFormat 对 象。然后,它创建标题、副标题和多列文本元素。 package com.example.programmingas3.newslayout { import flash.display.Sprite; import flash.text.StyleSheet; import flash.text.engine.*; import flash.events.Event; import flash.net.URLRequest; import flash.net.URLLoader; import flash.display.Sprite; import flash.display.Graphics; public class StoryLayout extends Sprite { public var headlineTxt:HeadlineTextField; public var subtitleTxt:HeadlineTextField; public var storyTxt:MultiColumnText; public var sheet:StyleSheet; public var h1_ElFormat:ElementFormat; public var h2_ElFormat:ElementFormat; public var p_ElFormat:ElementFormat; private var loader:URLLoader; public var paddingLeft:Number; public var paddingRight:Number; public var paddingTop:Number; public var paddingBottom:Number; public var preferredWidth:Number; public var preferredHeight:Number; public var numColumns:int; public var bgColor:Number = 0xFFFFFF; public var headline:String = "News Layout Example"; public var subtitle:String = "This example formats text like a newspaper page using the Flash Text Engine API. "; public var rawTestData:String = "From the part Mr. Burke took in the American Revolution, it was natural that I should consider him a friend to mankind; and as our acquaintance commenced on that ground, it would have been more agreeable to 353ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 me to have had cause to continue in that opinion than to change it. " + "At the time Mr. Burke made his violent speech last winter in the English Parliament against the French Revolution and the National Assembly, I was in Paris, and had written to him but a short time before to inform him how prosperously matters were going on. Soon after this I saw his advertisement of the Pamphlet he intended to publish: As the attack was to be made in a language but little studied, and less understood in France, and as everything suffers by translation, I promised some of the friends of the Revolution in that country that whenever Mr. Burke's Pamphlet came forth, I would answer it. This appeared to me the more necessary to be done, when I saw the flagrant misrepresentations which Mr. Burke's Pamphlet contains; and that while it is an outrageous abuse on the French Revolution, and the principles of Liberty, it is an imposition on the rest of the world. " + "I am the more astonished and disappointed at this conduct in Mr. Burke, as (from the circumstances I am going to mention) I had formed other expectations. " + "I had seen enough of the miseries of war, to wish it might never more have existence in the world, and that some other mode might be found out to settle the differences that should occasionally arise in the neighbourhood of nations. This certainly might be done if Courts were disposed to set honesty about it, or if countries were enlightened enough not to be made the dupes of Courts. The people of America had been bred up in the same prejudices against France, which at that time characterised the people of England; but experience and an acquaintance with the French Nation have most effectually shown to the Americans the falsehood of those prejudices; and I do not believe that a more cordial and confidential intercourse exists between any two countries than between America and France. "; public function StoryLayout(w:int = 400, h:int = 200, cols:int = 3, padding:int = 10):void { this.preferredWidth = w; this.preferredHeight = h; this.numColumns = cols; this.paddingLeft = padding; this.paddingRight = padding; this.paddingTop = padding; this.paddingBottom = padding; var req:URLRequest = new URLRequest("story.css"); loader = new URLLoader(); loader.addEventListener(Event.COMPLETE, onCSSFileLoaded); loader.load(req); } public function onCSSFileLoaded(event:Event):void { this.sheet = new StyleSheet(); this.sheet.parseCSS(loader.data); // convert headline styles to ElementFormat objects h1_ElFormat = getElFormat("h1", this.sheet); h1_ElFormat.typographicCase = TypographicCase.UPPERCASE; h2_ElFormat = getElFormat("h2", this.sheet); p_ElFormat = getElFormat("p", this.sheet); displayText(); } public function drawBackground():void { var h:Number = this.storyTxt.y + this.storyTxt.height + this.paddingTop + this.paddingBottom; var g:Graphics = this.graphics; g.beginFill(this.bgColor); g.drawRect(0, 0, this.width + this.paddingRight + this.paddingLeft, h); g.endFill(); } 354ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 /** * Reads a set of style properties for a named style and then creates * a TextFormat object that uses the same properties. */ public function getElFormat(styleName:String, ss:StyleSheet):ElementFormat { var style:Object = ss.getStyle(styleName); if (style != null) { var colorStr:String = style.color; if (colorStr != null && colorStr.indexOf("#") == 0) { style.color = colorStr.substr(1); } var fd:FontDescription = new FontDescription( style.fontFamily, style.fontWeight, FontPosture.NORMAL, FontLookup.DEVICE, RenderingMode.NORMAL, CFFHinting.NONE); var format:ElementFormat = new ElementFormat(fd, style.fontSize, style.color, 1, TextRotation.AUTO, TextBaseline.ROMAN, TextBaseline.USE_DOMINANT_BASELINE, 0.0, Kerning.ON, 0.0, 0.0, "en", BreakOpportunity.AUTO, DigitCase.DEFAULT, DigitWidth.DEFAULT, LigatureLevel.NONE, TypographicCase.DEFAULT); if (style.hasOwnProperty("letterSpacing")) { format.trackingRight = style.letterSpacing; } } return format; } public function displayText():void { headlineTxt = new HeadlineTextField(h1_ElFormat,headline,this.preferredWidth); headlineTxt.x = this.paddingLeft; 355ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 headlineTxt.y = 40 + this.paddingTop; headlineTxt.fitText(1); this.addChild(headlineTxt); subtitleTxt = new HeadlineTextField(h2_ElFormat,subtitle,this.preferredWidth); subtitleTxt.x = this.paddingLeft; subtitleTxt.y = headlineTxt.y + headlineTxt.height; subtitleTxt.fitText(2); this.addChild(subtitleTxt); storyTxt = new MultiColumnText(rawTestData, this.numColumns, 20, this.preferredWidth, this.preferredHeight, p_ElFormat); storyTxt.x = this.paddingLeft; storyTxt.y = subtitleTxt.y + subtitleTxt.height + 10; this.addChild(storyTxt); drawBackground(); } } } FormattedTextBlock.as 用作文本块创建的基类。它还包含用于更改字体大小和大小写的实用程序函数。 package com.example.programmingas3.newslayout { import flash.text.engine.*; import flash.display.Sprite; public class FormattedTextBlock extends Sprite { public var tb:TextBlock; private var te:TextElement; private var ef1:ElementFormat; private var textWidth:int; public var totalTextLines:int; public var blockText:String; public var leading:Number = 1.25; public var preferredWidth:Number = 720; public var preferredHeight:Number = 100; public function FormattedTextBlock(ef:ElementFormat,txt:String, colW:int = 0) { this.textWidth = (colW==0) ? preferredWidth : colW; blockText = txt; ef1 = ef; tb = new TextBlock(); tb.textJustifier = new SpaceJustifier("en",LineJustification.UNJUSTIFIED,false); te = new TextElement(blockText,this.ef1); tb.content = te; this.breakLines(); } private function breakLines() { var textLine:TextLine = null; var y:Number = 0; var lineNum:int = 0; while (textLine = tb.createTextLine(textLine,this.textWidth,0,true)) { textLine.x = 0; textLine.y = y; y += this.leading*textLine.height; this.addChild(textLine); 356ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 } for (var i:int = 0; i < this.numChildren; i++) { TextLine(this.getChildAt(i)).validity = TextLineValidity.STATIC; } this.totalTextLines = this.numChildren; } private function rebreakLines() { this.clearLines(); this.breakLines(); } private function clearLines() { while(this.numChildren) { this.removeChildAt(0); } } public function changeSize(size:uint=12):void { if (size > 5) { var ef2:ElementFormat = ef1.clone(); ef2.fontSize = size; te.elementFormat = ef2; this.rebreakLines(); } } public function changeCase(newCase:String = "default"):void { var ef2:ElementFormat = ef1.clone(); ef2.typographicCase = newCase; te.elementFormat = ef2; } } } HeadlineTextBlock.as 扩展 FormattedTextBlock 类,用于创建标题。它包含用于将文本放入已定义页面区域的函数。357ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 package com.example.programmingas3.newslayout { import flash.text.engine.*; public class HeadlineTextField extends FormattedTextBlock { public static var MIN_POINT_SIZE:uint = 6; public static var MAX_POINT_SIZE:uint = 128; public function HeadlineTextField(te:ElementFormat,txt:String,colW:int = 0) { super(te,txt); } public function fitText(maxLines:uint = 1, targetWidth:Number = -1):uint { if (targetWidth == -1) { targetWidth = this.width; } var pixelsPerChar:Number = targetWidth / this.blockText.length; var pointSize:Number = Math.min(MAX_POINT_SIZE, Math.round(pixelsPerChar * 1.8 * maxLines)); if (pointSize < 6) { // the point size is too small return pointSize; } this.changeSize(pointSize); if (this.totalTextLines > maxLines) { return shrinkText(--pointSize, maxLines); } else { return growText(pointSize, maxLines); } } public function growText(pointSize:Number, maxLines:uint = 1):Number { if (pointSize >= MAX_POINT_SIZE) { return pointSize; } this.changeSize(pointSize + 1); if (this.totalTextLines > maxLines) { // set it back to the last size this.changeSize(pointSize); return pointSize; } else { return growText(pointSize + 1, maxLines); } } 358ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 public function shrinkText(pointSize:Number, maxLines:uint=1):Number { if (pointSize <= MIN_POINT_SIZE) { return pointSize; } this.changeSize(pointSize); if (this.totalTextLines > maxLines) { return shrinkText(pointSize - 1, maxLines); } else { return pointSize; } } } } MultiColumnText.as 处理多列设计中的文本格式设置。它演示了 TextBlock 对象的灵活用法,该对象可作为用于创建文本 行、设置文本行格式以及放置文本行的工厂。 package com.example.programmingas3.newslayout { import flash.display.Sprite; import flash.text.engine.*; public class MultiColumnText extends Sprite { private var tb:TextBlock; private var te:TextElement; private var numColumns:uint = 2; private var gutter:uint = 10; private var leading:Number = 1.25; private var preferredWidth:Number = 400; private var preferredHeight:Number = 100; private var colWidth:int = 200; public function MultiColumnText(txt:String = "",cols:uint = 2, gutter:uint = 10, w:Number = 400, h:Number = 100, ef:ElementFormat = null):void { this.numColumns = Math.max(1, cols); this.gutter = Math.max(1, gutter); this.preferredWidth = w; this.preferredHeight = h; this.setColumnWidth(); var field:FormattedTextBlock = new FormattedTextBlock(ef,txt,this.colWidth); var totLines:int = field.totalTextLines; field = null; var linesPerCol:int = Math.ceil(totLines/cols); tb = new TextBlock(); te = new TextElement(txt,ef); tb.content = te; var textLine:TextLine = null; var x:Number = 0; var y:Number = 0; 359ACTIONSCRIPT 3.0 开发人员指南 使用 Flash 文本引擎 上次更新 2014/12/1 var i:int = 0; var j:int = 0; while (textLine = tb.createTextLine(textLine,this.colWidth,0,true)) { textLine.x = Math.floor(i/(linesPerCol+1))*(this.colWidth+this.gutter); textLine.y = y; y += this.leading*textLine.height; j++; if(j>linesPerCol) { y = 0; j = 0; } i++; this.addChild(textLine); } } private function setColumnWidth():void { this.colWidth = Math.floor( (this.preferredWidth - ((this.numColumns - 1) * this.gutter)) / this.numColumns); } } }360 上次更新 2014/12/1 第 23 章 : 使用 Text Layout Framework Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 Text Layout Framework 概述 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 Text Layout Framework (TLF) 是一种可扩展的 ActionScript 库。TLF 是在 Adobe® Flash® Player 10 和 Adobe® AIR® 1.5 中的文本引擎基础上构建而成的。 TLF 提供的高级排版和文本布局功能可以实现新颖的 Web 排版创意。该框架可与 Adobe® Flex® 或 Adobe® Flash® Professional 一起使用。开发人员可以使用或扩展现有组件,也可以使用该框架创建自己的文本组 件。 TLF 包含以下功能: • 双向文本、垂直文本以及 30 多种写作文种,包括阿拉伯文、希伯来文、中文、日文、韩文、泰文、老挝文、越南文和其他 文种 • 跨多个列和链接容器选择、编辑和流动文本 • 垂直文本、直排内横排 (在垂直文本内显示水平文本)以及在东亚排版规则中对齐文本 • 丰富的排版控件,包括字距微调、连字、印刷大小写、数字大小写、数字宽度和自由连字符 • 剪切、复制、粘贴、撤消以及标准的键盘和鼠标编辑手势 • 丰富的开发人员 API,用于操纵文本内容、布局、和标记以及创建自定文本组件 • 强大的列表支持,包括自定义标记和编号格式 • 内嵌图像和定位规则 TLF 是在 Flash Player 10 中引入的 Flash 文本引擎 (FTE) 基础上构建的一种 ActionScript 3.0 库。可以通过 flash.text.engine 包访问 FTE,该包是 Flash Player 10 应用程序编程接口 (API) 的一部分。 但是,Flash Player API 提供了对文本引擎的低级别访问,这意味着为了执行某些任务可能需要使用的代码相对比较多。TLF 将底层代码封装到更简单的 API 中。 TLF 还提供了一种概念体系结构,可以将 FTE 定义的基础构建块组织成易于使用的系 统。 与 FTE 不同, TLF 并未内置在 Flash Player 中,而是完全用 ActionScript 3.0 编写的一个独立组件库。由于此框架可扩展, 因此可针对特定环境对其进行自定义。 Flash Professional 和 Flex SDK 都包括基于 TLF 框架的组件。 更多帮助主题 “Flow”TLF 标记应用程序361ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 复杂文种支持 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 TLF 提供了复杂文种支持。复杂文种支持包括显示和编辑从右至左文种的功能。TLF 还提供了显示和编辑从左至右和从右至左 混合文种 (如阿拉伯文和希伯来文)的功能。此框架不仅支持适用于中文、日文和韩文的垂直文本布局,而且还支持直排内横 排(TCY 元素)。 TCY 元素是嵌入到垂直文本串的水平文本块。支持以下文种: • 拉丁文 (英文、西班牙文、法文、越南文等) • 希腊文、西里尔文、亚美尼亚文、格鲁吉亚文和埃塞俄比亚文 • 阿拉伯文和希伯来文 • 汉字象形和假名 (中文、日文和韩文)及 Hangul Johab (韩文) • 泰文、老挝文和高棉文 • 梵文、孟加拉文、果鲁穆奇文、马拉雅拉姆文、泰卢固文、泰米尔文、古吉特拉文、奥里雅文、卡纳达文和藏文 • 提非纳文、彝文、切罗基文、加拿大音节、德塞莱特文、萧伯纳字母、瓦伊文、塔加路文、哈努诺文、布迪文和塔格巴努亚 文 在 Flash Professional 和 Flex 中使用 Text Layout Framework 在 Flash 中,您可以直接使用 TLF 类创建自定义组件。此外, Flash Professional CS5 还提供了一个新的 fl.text.TLFTextField 类,该类封装了 TLF 功能。使用 TLFTextField 类可在 ActionScript 中创建使用 TLF 的高级文本显示 功能的文本字段。以与使用 TextField 类创建文本字段相同的方式创建 TLFTextField 对象。然后,使用 textFlow 属性从 TLF 类分配高级格式设置。 利用文本工具,还可以使用 Flash Professional 在舞台上创建 TLFTextField 实例。然后,可以使用 ActionScript 通过 TLF 类控制文本字段内容的格式和布局。有关更多信息,请参阅 《用于 Adobe Flash Platform 的 ActionScript 3.0 参考》中的 TLFTextField。 在 Flex 中工作时,请使用 TLF 类。有关更多信息,请参阅第 361 页的 “ 使用 Text Layout Framework”。 使用 Text Layout Framework Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在 Flex 中工作时或在构建自定义文本组件时,请使用 TLF 类。 TLF 是一种 ActionScript 3.0 库,它完全包含在 textLayout.swc 库中。 TLF 库包含约 100 个 ActionScript 3.0 类和接口,这些类和接口被组织到 10 个包中。这些包是 flashx.textLayout 包的子包。 Text Layout Framework 类 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 TLF 类划分为三种类别: • 数据结构和格式设置类 • 呈现类 • 用户交互类362ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 数据结构和格式设置类 下列包包含 TLF 的数据结构和格式设置类: • flashx.textLayout.elements • flashx.textLayout.formats • flashx.textLayout.conversion TLF 的主要数据结构为文本流层次结构,在元素包中定义。在该结构中,可以使用格式包为文本串指定样式和属性,也可以使 用转换包控制在数据结构中如何导入和导出文本。 呈现类 下列包包含 TLF 的呈现类: • flashx.textLayout.factory • flashx.textLayout.container • flashx.textLayout.compose 利用这些包中的类,可以方便地呈现文本以便在 Flash Player 中显示。工厂包提供显示静态文本的简便方式。容器包中的类和 接口用于定义动态文本的显示容器。组合包定义在容器中放置和显示动态文本的技术。 用户交互类 下列包包含 TLF 的用户交互类: • flashx.textLayout.edit • flashx.textLayout.operations • flashx.textLayout.events 编辑包和操作包定义了一些类,使用这些类可编辑在数据结构中存储的文本。事件包中包含事件处理类。 使用 Text Layout Framework 创建文本的常规步骤 下列步骤介绍了创建带有文本布局格式的文本的常规过程: 1 将带格式文本导入到 TLF 数据结构中。有关更多信息,请参阅第 365 页的 “ 使用 TLF 构建文本结构 ” 和第 369 页的 “ 使用 TLF 设置文本格式 ”。 2 为文本创建一个或多个链接的显示对象容器。有关更多信息,请参阅第 370 页的 “ 使用 TLF 管理文本容器 ”。 3 将数据结构中的文本与容器关联并设置编辑和滚动选项。有关更多信息,请参阅第 371 页的 “ 使用 TLF 启用文本选择、编 辑和撤消 ”。 4 在响应 resize (或其他)事件时,创建事件处理函数以重排文本。有关更多信息,请参阅第 372 页的 “ 使用 TLF 处理事件 ”。 Text Layout Framework 示例:新闻版面布局 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 以下示例演示了如何使用 TLF 设置简单的新闻页面的布局。该页包含大标题、副标题和包含多列的正文部分:363ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 package { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.geom.Rectangle; import flashx.textLayout.compose.StandardFlowComposer; import flashx.textLayout.container.ContainerController; import flashx.textLayout.container.ScrollPolicy; import flashx.textLayout.conversion.TextConverter; import flashx.textLayout.elements.TextFlow; import flashx.textLayout.formats.TextLayoutFormat; public class TLFNewsLayout extends Sprite { private var hTextFlow:TextFlow; private var headContainer:Sprite; private var headlineController:ContainerController; private var hContainerFormat:TextLayoutFormat; private var bTextFlow:TextFlow; private var bodyTextContainer:Sprite; private var bodyController:ContainerController; private var bodyTextContainerFormat:TextLayoutFormat; private const headlineMarkup:String = "TLF News Layout ExampleThis example formats text like a newspaper page with a headline, a subtitle, and multiple columns"; private const bodyMarkup:String = "There are many such lime-kilns in that tract of country, for the purpose of burning the white marble which composes a large part of the substance of the hills. Some of them, built years ago, and long deserted, with weeds growing in the vacant round of the interior, which is open to the sky, and grass and wild-flowers rooting themselves into the chinks of the stones, look already like relics of antiquity, and may yet be overspread with the lichens of centuries to come. Others, where the lime-burner still feeds his daily and nightlong fire, afford points of interest to the wanderer among the hills, who seats himself on a log of wood or a fragment of marble, to hold a chat with the solitary man. It is a lonesome, and, when the character is inclined to thought, may be an intensely thoughtful occupation; as it proved in the case of Ethan Brand, who had mused to such strange purpose, in days gone by, while the fire in this very kiln was burning.The man who now watched the fire was of a different order, and troubled himself with no thoughts save the very few that were requisite to his business. At frequent intervals, he flung back the clashing weight of the iron door, and, turning his face from the insufferable glare, thrust in huge logs of oak, or stirred the immense brands with a long pole. Within the furnace were seen the curling and riotous flames, and the burning marble, almost molten with the intensity of heat; while without, the reflection of the fire quivered on the dark intricacy of the surrounding forest, and showed in the foreground a bright and ruddy little picture of the hut, the spring beside its door, the athletic and coal-begrimed figure of the lime-burner, and the half-frightened child, shrinking into the protection of his father's shadow. And when again the iron door was closed, then reappeared the tender light of the half-full moon, which vainly strove to trace out the indistinct shapes of the neighboring mountains; and, in the upper sky, there was a flitting congregation of clouds, still faintly tinged with the rosy sunset, though thus far down into the valley the sunshine had vanished long and long ago."; public function TLFNewsLayout() { //wait for stage to exist 364ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); } private function onAddedToStage(evtObj:Event):void { removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; // Headline text flow and flow composer hTextFlow = TextConverter.importToFlow(headlineMarkup, TextConverter.TEXT_LAYOUT_FORMAT); // initialize the headline container and controller objects headContainer = new Sprite(); headlineController = new ContainerController(headContainer); headlineController.verticalScrollPolicy = ScrollPolicy.OFF; hContainerFormat = new TextLayoutFormat(); hContainerFormat.paddingTop = 4; hContainerFormat.paddingRight = 4; hContainerFormat.paddingBottom = 4; hContainerFormat.paddingLeft = 4; headlineController.format = hContainerFormat; hTextFlow.flowComposer.addController(headlineController); addChild(headContainer); stage.addEventListener(flash.events.Event.RESIZE, resizeHandler); // Body text TextFlow and flow composer bTextFlow = TextConverter.importToFlow(bodyMarkup, TextConverter.TEXT_LAYOUT_FORMAT); // The body text container is below, and has three columns bodyTextContainer = new Sprite(); bodyController = new ContainerController(bodyTextContainer); bodyTextContainerFormat = new TextLayoutFormat(); bodyTextContainerFormat.columnCount = 3; bodyTextContainerFormat.columnGap = 30; bodyController.format = bodyTextContainerFormat; bTextFlow.flowComposer.addController(bodyController); addChild(bodyTextContainer); resizeHandler(null); } private function resizeHandler(event:Event):void { const verticalGap:Number = 25; const stagePadding:Number = 16; var stageWidth:Number = stage.stageWidth - stagePadding; var stageHeight:Number = stage.stageHeight - stagePadding; var headlineWidth:Number = stageWidth; var headlineContainerHeight:Number = stageHeight; // Initial compose to get height of headline after resize headlineController.setCompositionSize(headlineWidth, headlineContainerHeight); hTextFlow.flowComposer.compose(); 365ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 var rect:Rectangle = headlineController.getContentBounds(); headlineContainerHeight = rect.height; // Resize and place headline text container // Call setCompositionSize() again with updated headline height headlineController.setCompositionSize(headlineWidth, headlineContainerHeight ); headlineController.container.x = stagePadding / 2; headlineController.container.y = stagePadding / 2; hTextFlow.flowComposer.updateAllControllers(); // Resize and place body text container var bodyContainerHeight:Number = (stageHeight - verticalGap - headlineContainerHeight); bodyController.format = bodyTextContainerFormat; bodyController.setCompositionSize(stageWidth, bodyContainerHeight ); bodyController.container.x = (stagePadding/2); bodyController.container.y = (stagePadding/2) + headlineContainerHeight + verticalGap; bTextFlow.flowComposer.updateAllControllers(); } } } TLFNewsLayout 类使用两个文本容器。一个容器显示大标题和副标题,另一个容器显示包含三列的正文文本。为简洁起见, 文本作为 TLF 标记文本硬编码到示例中。headlineMarkup 变量包含标题和副标题,bodyMarkup 变量包含正文文本。有关 TLF 标记的更多信息,请参阅第 365 页的 “ 使用 TLF 构建文本结构 ”。 在完成一些初始化操作之后,onAddedToStage() 函数将大标题文本导入到 TextFlow 对象中,该对象是 TLF 的主要数据结构: hTextFlow = TextConverter.importToFlow(headlineMarkup, TextConverter.TEXT_LAYOUT_FORMAT); 接下来,为容器创建 Sprite 对象,然后为容器创建控制器并将该控制器与容器相关联: headContainer = new Sprite(); headlineController = new ContainerController(headContainer); 初始化控制器以设置格式、滚动和其他选项。控制器包含相关的几何尺寸设置,用于定义文本流入的容器的边界。 TextLayoutFormat 对象包含格式选项: hContainerFormat = new TextLayoutFormat(); 控制器分配给了流合成器,该函数将容器添加到显示列表。容器的实际构成和显示会延迟到 resizeHandler() 方法。按相同顺序 执行相关步骤以初始化正文的 TextFlow 对象。 resizeHandler() 方法测量可供呈现容器用的空间并相应地设置容器大小。首先,调用 compose() 方法,以便计算标题容器的合 适高度。随后, resizeHandler() 方法可以使用 updateAllControllers() 方法添加和显示标题容器。最后, resizeHandler() 方法使 用标题容器的大小确定正文文本容器的位置。 使用 TLF 构建文本结构 TLF 使用层次树来表示文本。树中的每个节点都是元素包中定义的类的实例。例如,树的根节点始终是 TextFlow 类的实例。 TextFlow 类表示整个文本素材。文章是文本和其他元素的集合,可将其视为一个单元或流。一篇文章可能需要使用多个列或 文本容器进行显示。 除了根节点,其余元素大致基于 XHTML 元素。下图显示了该框架的层次结构:366ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 TextFlow 层次结构 Text Layout Framework 标记 了解 TLF 的结构在处理 TLF 标记时也很有用。 TLF 标记是文本的 XML 表示形式,作为 TLF 一部分包含在其中。虽然该框 架也支持其他 XML 格式,但 TLF 标记是唯一专门基于 TextFlow 层次结构的一种格式。如果您使用此标记格式从 TextFlow 导出 XML,则导出 XML 时会保持此层次结构的完整性。 TLF 标记为 TextFlow 层次结构中的文本提供了最高保真度的表示形式。标记语言为 TextFlow 层次结构的每个基本元素提供 标签,并为 TextLayoutFormat 类中的所有可用格式设置属性提供特性。 下表包含可以在 TLF 标记中使用的标签。 元素 说明 子代 类 textflow 标记的根元素。 div、 pTextFlow div TextFlow 内的分割块。可以包含一组段落。 div、 list、 p DivElement p 段落。 a、 tcy、 span、 img、 tab、 br、 g ParagraphElement a 链接。 tcy、 span、 img、 tab、 br、 g LinkElement tcy 水平文本串 (用于垂直 TextFlow 中)。 a、 span、 img、 tab、 br、 g TCYElement span 段落内的文本串。 SpanElement img 段落中的图像。 InlineGraphicElemen t tab 制表符字符。 TabElement br 分隔符。用于在段落内结束一行;文本在下一行 中继续,仍位于同一段落中。 BreakElement linkNormalFormat 定义用于处于正常状态的链接的格式属性。 TextLayoutFormat TextLayoutFormat linkActiveFormat 在链接上按下鼠标时,定义用于处于活动状态的 链接的格式属性。 TextLayoutFormat TextLayoutFormat linkHoverFormat 当鼠标位于链接边界内时 (滚过),定义用于处 于悬停状态的链接的格式属性。 TextLayoutFormat TextLayoutFormat367ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 更多帮助主题 TLF 2.0 列表标记 TLF 2.0 SubParagraphGroupElements 和 typeName 使用编号列表和项目列表 可以使用 ListElement 和 ListItemElement 类将项目列表添加到文本控件。可以嵌套项目列表,也可以对其进行自定义以使 用不同的项目符号 (或标记)和自动编号以及轮廓样式编号。 若要在文本流中创建列表,请使用 标签。然后,对于列表中的每个列表项,您可以在 标签内使用
  • 标签。可以 使用 ListMarkerFormat 类自定义项目符号的外观。 下面的示例会创建简单的列表: Item 1 Item 2 Item 3 您可以在其他列表中嵌套列表,如下面的示例所示: Item 1 Item 1a Item 1b Item 1c Item 2 Item 3 若要自定义列表中标记的类型,请使用 ListElement 的 listStyleType 属性。此属性可以是 ListStyleType 类定义的任意值(如 check、 circle、 decimal 和 box)。下面的示例使用多种标记类型和一个自定义计数器增量创建列表: upperAlpha item another lowerAlpha item another upperRoman item another lowerRoman item another 使用 ListMarkerFormat 类可以定义计数器。除了定义计数器的增量,您还可以利用 counterReset 属性重新设置计数器,从而 对其进行自定义。 可以使用 ListMarkerFormat 的 beforeContent 和 afterContent 属性对列表中标记的外观进行进一步自定义。这些属性会应用 到显示在标记内容之前和之后的内容。 li 一个列表项目元素。必须位于一个列表元素内。 div、 li、 list、 p ListItemElement list 一个列表。列表可以嵌套,或者放置得距离彼此 很近。列表项目可以应用不同的标签或编号方 案。 div、 li、 list、 p ListElement g 组元素。用于对段落中的元素进行分组。允许您 在段落级别以下嵌套元素。 a、 tcy、 span、 img、 tab、 br、 g SubParagraphGroup Element 元素 说明 子代 类368ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 下面的示例会在标记之前添加字符串 “XX”,在标记之后添加字符串 “YY”: Item 1 Item 2 Item 3 content 属性本身可以定义标记格式的更多自定义内容。下面的示例会显示一个有序的、大写 Roman 数字标记: Item 1
  • Item 2 Item 3 如上个示例所示, content 属性还可以插入一个后缀:一个在标记后、但在 afterContent 之前显示的字符串。若要在向流提供 XML 内容时插入此字符串,请使用 "e; HTML 实体而不是引号 ("") 来包括此字符串。 更多帮助主题 TLF 2.0 列表标记 在 TLF 中使用填充 每个 FlowElement 支持您使用的填充属性,来控制每个元素的内容区域的位置以及内容区域之间的间距。 某个元素的总宽度是其内容宽度的总和加上 paddingLeft 和 paddingRight 属性。某个元素的总高度是其内容高度的总和加上 paddingTop 和 paddingBottom 属性。 填充是指边框和内容之间的间距。填充属性包括有 paddingBottom、paddingTop、paddingLeft 和 paddingRight。可以将填充应 用于 TextFlow 对象和以下子元素: • div • img • li • list • p 填充属性不能应用到范围元素。 下面的示例将设置 TextFlow 的填充属性: 369ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 填充属性的有效值包括数值 (以像素为单位)、 “auto” 或 “inherit”。默认值为 “auto”,表示该值是自动计算得出,对所有元 素均设置为 0,ListElement 除外。对于 ListElements,“auto” 为 0,使用 listAutoPadding 属性的值所在列表的起始侧除外。 listAutoPadding 的默认值为 40,这是为列表指定的默认缩进。 默认情况下,填充属性不会继承。 “auto” 和 “inherit” 值是由 FormatValue 类定义的常数。 填充属性可以为负值。 更多帮助主题 TLF 2.0 中对填充所做的更改 使用 TLF 设置文本格式 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 flashx.textLayout.formats 包中包含一些接口和类,使用这些接口和类,您可以为文本流层次树中的任何 FlowElement 指定 格式。可通过两种方式应用格式设置。您可以分别指定某特定格式,也可以利用特殊格式设置对象同时指定一组格式。 ITextLayoutFormat 接口包含可以应用于 FlowElement 的所有格式。有些格式应用于文本的某一完整容器或段落,但不会在 逻辑上应用于各个字符。例如,字距调整和制表符这样的格式应用于全部段落,但不应用于各个字符。 使用属性为 FlowElement 指定格式 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 您可以通过属性分配对任何 FlowElement 设置格式。FlowElement 类实现 ITextLayoutFormat 接口,因此 FlowElement 类的任一子类也必须实现该接口。 例如,以下代码显示如何为 ParagraphElement 实例指定单种格式: var p:ParagraphElement = new ParagraphElement(); p.fontSize = 18; p.fontFamily = "Arial"; 使用 TextLayoutFormat 类为 FlowElement 指定格式 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 您可以使用 TextLayoutFormat 类向 FlowElement 应用格式。可使用此类创建包含所需的所有格式设置值的特定格式设置对 象。然后,将该对象指定给任何 FlowElement 对象的 format 属性。 TextLayoutFormat 和 FlowElement 都实现 ITextLayoutFormat 接口。这种安排确保两个类都包含同样的格式属性。 有关更多信息,请参阅 《用于 Adobe Flash Platform 的 ActionScript 3.0 参考》中的 TextLayoutFormat。370ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 格式继承 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 通过文本流层次结构继承格式。如果将 TextLayoutFormat 的实例指定给带有子代的 FlowElement 实例,框架将启动一个称 为级联的过程。在级联过程中,框架递归检查从您的 FlowElement 继承的层次中的每个节点。然后,它确定是否将继承的值 指定给各格式设置属性。在级联过程中应用下列规则: 1 属性值只从直接祖先 (有时称为父代)继承。 2 仅当属性尚未设置值 (即该值为 undefined)时,才继承属性值。 3 一些属性在未定义时不继承值,除非将属性的值设置为 “ 继承 ” 或常量 flashx.textLayout.formats.FormatValue.INHERIT。 例如,如果在 TextFlow 级别设置 fontSize 值,则该设置将应用于 TextFlow 中的所有元素。换句话说,这些值按照文本流层 次向下级联。不过,您可以通过直接对给定元素指定新值来覆盖该元素中的值。举个反例,如果您在 TextFlow 级别设置 backgroundColor 值,TextFlow 的子项不继承该值。backgroundColor 属性不是级联期间从其父项继承的。通过将每一子项中 的 backgroundColor 属性设置为 flashx.textLayout.formats.FormatValue.INHERIT,可以覆盖此行为 . 有关更多信息,请参阅 《用于 Adobe Flash Platform 的 ActionScript 3.0 参考》中的 TextLayoutFormat。 使用 TLF 导入和导出文本 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 flashx.textLayout.conversion 中的 TextConverter 类。* 包允许您将文本导入到 TLF 以及从 TLF 导出文本。如果打算在运 行时加载文本,而不是将文本编译到 SWF 文件中,请使用此类。您也可以使用此类将存储在 TextFlow 实例中的文本导出到 一个字符串或 XML 对象。 导入和导出过程都直接完成。可以调用 export() 方法或 importToFlow() 方法,这两个方法都属于 TextConverter 类。这两个 方法都是静态方法,意味着您对 TextConverter 类调用这两个方法,而非对 TextConverter 类的实例调用它们。 flashx.textLayout.conversion 包中的类在选择文本存储位置方面提供了极大的灵活性。例如,如果将文本存储在数据库中, 您可以将文本导入该框架中以供显示。然后,可以使用 flashx.textLayout.edit 包中的类更改文本,并将更改后的文本导回到 数据库中。 有关更多信息,请参阅 《用于 Adobe Flash Platform 的 ActionScript 3.0 参考》中的 flashx.textLayout.conversion。 使用 TLF 管理文本容器 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 将文本存储在 TLF 数据结构中后, Flash Player 可以显示这些文本。必须将流层次结构中存储的文本转换为 Flash Player 可 以显示的格式。 TLF 提供了两种从流中创建显示对象的方法。第一种方法较为简单,适用于显示静态文本。第二种方法较为复 杂,允许您创建可进行选择和编辑的动态文本。使用这两种方法,文本最终都会转换为 TextLine 类的实例, TextLine 类保存 在 Flash Player 10 中的 flash.text.engine.* 包中。 创建静态文本 此简单方法使用 TextFlowTextLineFactory 类,该类位于 flashx.textLayout.factory 包中。此方法不仅简单,比 FlowComposer 方法占用的内存也少。建议对不需要用户编辑、选择或滚动的静态文本使用此方法。371ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 有关更多信息,请参阅 《用于 Adobe Flash Platform 的 ActionScript 3.0 参考》中的 TextFlowTextLineFactory。 创建动态文本和容器 如果您要加大对文本显示的控制程度 (而不是由 TextFlowTextLineFactory 提供的控制程度),请使用流合成器。例如,使 用流合成器,用户可以选择和编辑文本。有关更多信息,请参阅第 371 页的 “ 使用 TLF 启用文本选择、编辑和撤消 ”。 流合成器是 flashx.textLayout.compose 包中的 StandardFlowComposer 类的实例。流合成器管理 TextFlow 到 TextLine 实例的转换,并负责将这些 TextLine 实例放置到一个或多个容器中。 IFlowComposer 包含零个或更多 ContainerController 每个 TextFlow 实例都有一个可实现 IFlowComposer 接口的相应对象。可以通过 TextFlow.flowComposer 属性访问此 IFlowComposer 对象。可以通过此属性调用 IFlowComposer 接口定义的方法。使用这些方法,可以将文本与一个或多个容 器关联并准备好要在容器中显示的文本。 容器是 Sprite 类 (该类是 DisplayObjectContainer 类的子类)的实例。这两个类都包含在 Flash Player 显示列表 API 中。 容器是定界矩形的更高级形式,与 TextLineFactory 类一起使用。与定界矩形类似,容器定义显示 TextLine 实例的区域。与 定界矩形不同,容器具有对应的 “ 控制器 ” 对象。控制器管理一个容器或一组容器的滚动、合成、格式设置和事件处理。每个 容器有一个对应的控制器对象,该对象是 flashx.textLayout.container 包中 ContainerController 类的实例。 若要显示文本,请创建一个控制器对象来管理该容器,并将其与流合成器关联。关联容器之后,编写文本以使文本能显示出 来。相应地,容器有两种状态:编写和显示。编写是将文本流层次中的文本转换为 TextLine 实例并计算这些实例是否适合容 器的过程。显示是更新 Flash Player 显示列表的过程。 有关更多信息,请参阅 《用于 Adobe Flash Platform 的 ActionScript 3.0 参考》中的 IFlowComposer、 StandardFlowComposer 和 ContainerController。 使用 TLF 启用文本选择、编辑和撤消 Flash Player 9.0 和更高版本, Adobe AIR 1.0 和更高版本 在文本流级别控制选择或编辑文本的能力。 TextFlow 类的每个实例都有一个关联的交互管理器。可通过对象的 TextFlow.interactionManager 属性访问 TextFlow 对象的交互管理器。要启用文本选择功能,可将 SelectionManager 类的实 例指定给 interactionManager 属性。要启用文本选择和编辑功能,可指定 EditManager 类的实例,而不是指定 SelectionManager 类的实例。要启用撤消操作,可创建 UndoManager 类的一个实例,并将其纳为调用 EditManager 的构 造函数时的参数。 UndoManager 类维护用户最新编辑活动的历史记录,并允许用户撤消或重做特定的编辑操作。上述所有三 个类都包含在编辑包中。 有关更多信息,请参阅 《用于 Adobe Flash Platform 的 ActionScript 3.0 参考》中的 SelectionManager、 EditManager 和 UndoManager。 IFlowComposer ContainerController TextFlow TextLine TextLine Stage Sprite372ACTIONSCRIPT 3.0 开发人员指南 使用 Text Layout Framework 上次更新 2014/12/1 使用 TLF 处理事件 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 在许多情况下, TextFlow 对象都会调度事件,包括: • 当文本或布局发生更改时 • 在操作开始之前或操作完成之后 • 当 FlowElement 对象的状态发生更改时 • 当合成操作完成时 有关更多信息,请参阅 《用于 Adobe Flash Platform 的 ActionScript 3.0 参考》中的 flashx.textLayout.events。 更多帮助主题 TLF FlowElement 和 LinkElement 事件以及 EventMirrors 在文本内定位图像 若要在文本内定位 InlineGraphicElement,您可以使用以下属性: • InlineGraphicElement 类的 float 属性 • FlowElement 的 clearFloats 属性 float 属性控制着图形及其周围文本的放置。 clearFloats 属性控制着段落元素相对于 float 的放置。 要控制文本元素内某个图像的位置,可以使用 float 属性。下面的示例向段落中添加一个图像,并将其与左侧对齐,从而使文本 在右侧自动换行: Images in a flow are a good thing. For example, here is a float. It should show on the left: Don't you agree? Another sentence here. Another sentence here. Another sentence here. Another sentence here. Another sentence here. Another sentence here. Another sentence here. Another sentence here. float 属性的有效值包括:“left”、 “right”、 “start”、 “end” 和 “none”。 Float 类定义了这些常数。默认值为 “none”。 要为那些通常环绕在图像周围的后续段落调整起始位置, clearFloats 属性很有用。例如,假设您有一个图像,其尺寸大于第一 个段落。要确保第二个段落起始于该图像后面,请设置 clearFloats 属性。 下面的示例使用的图像高于第一个段落中的文本。为使第二个段落起始于文本区块中的图像之后,此示例将第二个段落的 clearFloats 属性设置为 “end”。 Here is another float, it should show up on the right: We'll add another paragraph that should clear past it.This should appear after the previous float on the right. clearFloats 属性的有效值包括:“left”、“right”、“end”、“start”、“none” 和 “both”。ClearFloats 类定义这些常数。您还可 以将 clearFloats 属性设置为 “inherit”,这是一个由 FormatValue 类定义的常数。默认值为 “none”。 更多帮助主题 TLF 浮动373 上次更新 2014/12/1 第 24 章 : 处理声音 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ActionScript 是为开发引人入胜的交互式应用程序而设计的,这种极其引人入胜的应用程序中经常被忽略的一