注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

无线时代辐射无穷

抓紧生宝宝,小心辐射

 
 
 

日志

 
 

flex4.5效果:为多个屏幕大小创作移动 Flash 内容  

2011-06-18 19:40:25|  分类: flex |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

随着 Flash Platform 继续增生并延伸到更多设备,开发人员在采用创作技术时需要兼顾多个屏幕大小和分辨率。本文讨论帮助 Flash 开发人员创作内容的多种技术,这些内容可以在任何设备上正确呈现,无论设备的屏幕分辨率及像素密度如何。

本文讨论的技术有些“低级”,因为它们展示了矢量的程序化创建以及将算法(虽然是一些简单算法)用于动态大小和位置资源。某些应用程序始终需要这类创作控件,但今后也会出现“更高级”、更简单的其他选择。

Adobe 目前正在开发一个移动 Flex 框架(代号为“Slider”),它可以自动应用此处讨论的一些技术,使您能更轻松地编写出可适应不同屏幕的应用程序。但在 Slider 推出之前,对于应用程序无法适应现有框架模型的人而言,本文讨论的提示与技巧可以帮助您快速启动多屏幕开发。

必备知识

本文假设您熟悉 ActionScript 3。

术语

在开始探索针对多个屏幕大小、基于 SWF 的应用程序的具体创作技术之前,有必要温习一下相关术语。您或许了解这些术语的普通含义,但要实际运用它们则有必要彻底理解它们:

  • 屏幕大小:屏幕大小就是指屏幕的对角线长度,通常以英寸为单位。虽然屏幕大小与分辨率及 PPI 有关,但是您无法仅从屏幕大小判断出屏幕的分辨率或 PPI。
  • 分辨率:屏幕或显示屏分辨率是指屏幕在每个维度包含的像素数。Motorola Droid 的屏幕分辨率为 480x854。我现在使用的 27" 外置显示器的分辨率为 1920x1200。将两个维度的像素数相乘就可以得出屏幕能显示的总像素数。
  • PPIDPI 和像素密度:PPI(每英寸像素数)、DPI(每英寸点数)和像素密度都是指同一概念:每个物理距离单元的像素数(在一个维度上)。可能难以相信这是多屏幕大小创作的一个重要属性,但正如我接下来要解释的,PPI 的重要性不亚于分辨率,有时甚至更重要。

应用程序架构

多屏幕应用程序并不一定要在每个设备上外观相同;相反,它应当适应安装所在的任何设备。换言之,多屏幕应用程序应当动态调整为主机设备的分辨率和 PPI,在较大的屏幕上显示更多信息,在较小的屏幕上删除或缩小元素,确保按钮大小足够用户轻触,等等。为了确保应用程序能跨不同的屏幕运行,它们必须采用特定的架构,在适当的时刻使用适当的限制绘制和重绘自己。

Stage 比例模式和对齐方式

在进行应用程序布局之前,必须设置 Stage 的比例模式和对齐方式。应当在注册 Stage 调整大小事件(以下详述)之前或之后,通过 Sprite 的构造函数完成这一操作:

  1. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  2. this.stage.align = StageAlign.TOP_LEFT;

将 Stage 的比例模式设置为 NO_SCALE 表明您不希望自己的内容发生任何自动缩放或布局,并且您将自己处理所有布局和缩放。这使得应用程序能动态调整自己,从而适应不同的屏幕大小。
将 Stage 的 align 属性设置为 TOP_LEFT 表明您希望相对于坐标为 0,0 的左上角进行内容布局。

侦听 Stage 调整大小事件

多屏幕应用程序中进行渲染的最佳位置是在 Stage 调整大小事件处理函数中。当初始化应用程序及设置 Stage(应用程序工作的区域)的大小时,Stage 将调度一个调整大小事件。在一个纯 ActionScript 应用程序中,您将在主 Sprite 的构造函数中侦听 Stage 调整大小事件,如下:

this.stage.addEventListener(Event.RESIZE,  doLayout);

在 Stage 上注册调整大小事件后,每次调整 Stage 的大小时会调用 doLayout。例如:

  • 第一次初始化应用程序时。
  • 调整窗口大小时(在桌面上运行时)。
  • 设备改变方向时。

通过在 Stage 调整大小事件处理函数中执行布局,每当 Stage 的大小发生变化时,您的应用程序会自动进行自我布局,无论变化的原因如何。

注意:要确定 Stage 的大小,请使用 stage.stageWidth 和 stage.stageHeight 属性。无需使用 SWF 元数据设置 SWF 文件的维度。事实上,这样做可能在初始化应用程序时导致调整大小事件处理函数无法被调用。最好在应用程序描述符文件的初始窗口部分设置应用程序的宽度和高度,如下:

  1. <initialWindow>
  2. <width>320</width>
  3. <height>480</height>
  4. <!-- several other properties... -->
  5. </initialWindow>

确定资源大小

设计为在屏幕大小及分辨率不同的设备上运行的应用程序往往需要动态确定资源大小。换言之,某个设备上外观和使用达到最佳程度的按钮在分辨率更高的设备上可能因为太小而无法看清或轻触。因此,开发人员必须了解如何从像素和英寸出发进行思考。

从像素出发进行思考

要为一个应用程序添加纯色背景,只需要从像素出发进行思考。例如,屏幕大小没有关系,背景始终需要与屏幕的像素维度保持匹配。以下代码说明如何将纯色背景添加到一个任意大小的应用程序:

  1. var bg:Sprite = new Sprite();
  2. bg.x = 0;
  3. bg.y = 0;
  4. bg.graphics.beginFill(0x006E59);
  5. bg.graphics.drawRect(0, 0, this.stage.stageWidth,
  6.    this.stage.stageHeight);
  7.    this.addChild(bg);

Stage 对象上的 stageWidth 和 stageHeight 属性表明内容的 Stage 的像素维度。要创建一个可用于任意尺寸的设备上任意大小的应用程序的背景,您只需要这一信息。

从物理单位出发进行思考

当资源可以相对设置大小(如,背景)时,设置资源像素大小是可行的,但需要绝对设置资源大小时却不行。 换言之,只要背景的大小为整个 Stage,它的大小就没有关系;但是,需要更精确地控制字体和按钮等的大小。这时,必须从物理单元或 PPI 出发进行思考。

英寸

使用 PPI 确定资源的维度使您能控制资源的确切大小,无论渲染它的是哪种屏幕。例如,要创建一个始终为 ?" x ?" 的按钮(无论在较大的台式显示器还是较小的手机屏幕上渲染它),您必须使用屏幕的 PPI。

注意:为了实现一致、可靠的点击,研究表明点击目标不应小于 ?" 或 7 毫米。确保按钮可以跨设备使用的唯一途径是从物理单位出发进行思考。

当前屏幕的 PPI 可由 Capabilities.screenDPI 属性决定。当然,资源最终始终按像素而不是英寸设置大小,因此必须将 PPI 转换为像素。我使用以下这个简单的实用程序函数:

  1. /**
  2.   * Convert inches to pixels.
  3.   */
  4. private function inchesToPixels(inches:Number):uint
  5. {
  6.    return Math.round(Capabilities.screenDPI * inches);
  7. }

以下代码说明了如何创建一个在任何设备上显示为 ?" x ?" 的 sprite:

  1. var button:Sprite = new Sprite();
  2. button.x = 20;
  3. button.y = 20;
  4. button.graphics.beginFill(0x 003037);
  5. button.graphics.drawRect(0, 0, this.inchesToPixels(.75),
  6.    this.inchesToPixels(.25));
  7. button.graphics.endFill();
  8.    this.addChild(button);

公制

为了不要过于侧重于美式标准,并且公制体系在较小比例方面的出色表现,以下是一个将毫米转换为像素的版本:

  1. /**
  2.   * Convert millimeters to pixels.
  3.   */
  4. private function mmToPixels(mm:Number):uint
  5. {
  6.    return Math.round(Capabilities.screenDPI * (mm / 25.4));
  7. }

动态布局

应用程序现在的架构方式使它能创作为适合多个屏幕大小,并且您已获得确定资源大小的技术,所以可以开始进行资源布局了。
为能适应不同的屏幕大小进行资源布局的关键在于确定根据当前屏幕的属性要硬编码的内容以及要计算的内容。例如,要在应用程序顶部创建一个标题栏,您希望 x 和 y 坐标为 0,0,即这些属性可以硬编码。换言之,无论应用程序运行在什么设备上,您始终希望标题栏位于左上角。以下代码说明新建一个用作标题栏的 Sprite 并将其位置硬编码:

  1. var titleBar:Sprite = new Sprite();
  2. titleBar.x = 0;
  3. titleBar.y = 0;

虽然标题栏的位置不会随设备不同而异,它的宽度会改变。在高分辨率设备上,宽度必须更大。
确定标题栏的宽度与使用 stage.stageWidth 属性一样简单,那么高度呢?您可以按像素将高度硬编码,但高度大小将根据分辨率随设备不同而大幅改变。这种情况下,更好的方法是从物理单位出发进行思考,使标题栏能跨所有设备呈现一致的外观。
以下代码创建的标题栏说明了以下所有概念:

  • 在合适时将一个绝对位置硬编码
  • 使用 stage.stageWidth 按像素动态确定标题栏的宽度
  • 以英寸为单位设置标题栏高度,从而确保一致的跨设备外观

  1. var titleBar:Sprite = new Sprite();
  2. titleBar.x = 0;
  3. titleBar.y = 0;
  4. titleBar.graphics.beginFill(0x003037);
  5. titleBar.graphics.drawRect(0, 0, this.stage.stageWidth,
  6. this.inchesToPixels(.3));
  7. titleBar.graphics.endFill();
  8. this.addChild(titleBar);

以上示例说明了如何动态设置资源大小,那么它们的动态定位呢?例如,标题栏总是从左上角开始,所以它的定位不用多说,那么 x 坐标始终为 0、而 y 坐标由 Stage 高度决定的脚注的定位呢?
以下代码说明了如何创建一个脚注,它始终横跨整个应用程序的宽度,并且总在底部,无论屏幕的高度如何:

  1. var footer:Sprite = new Sprite();
  2. footer.graphics.beginFill(0x003037);
  3. footer.graphics.drawRect(0, 0, this.stage.stageWidth,
  4. this.inchesToPixels(.3));
  5. footer.graphics.endFill();
  6. footer.x = 0;
  7. footer.y = this.stage.stageHeight - footer.height;
  8. this.addChild(footer);

相对定位

资源主要有三种布局方式(我已说明其中两种):

  • 像我们在应用程序的背景和标题栏中那样使用硬编码位置
  • 像我们在应用程序脚注中那样计算位置
  • 根据其他资源计算位置

根据称为相对定位的另一个资源计算资源的位置,这是设计多屏幕应用程序的一项极其重要的技术。回到标题栏示例,我们成功创建了一个始终能如您所愿定位和呈现的标题栏,那么标题本身呢?您始终可以硬编码一个 y 位置,可以将它放在顶部以下几个像素的地方,然后根据 Stage 宽度和标题宽度计算一个 x 坐标,但这样无法始终获得最佳效果,原因有二:

  • 标题栏高度会随屏幕 PPI 的不同而变化,文本无法始终垂直居中。
  • 如果出于任何原因(例如,如果决定去掉脚注并将标题栏放到底部),您决定移动标题栏,还必须更改标题代码。

将标题相对标题栏放置可以解决这两个问题。由于这是我经常需要的操作,我用一个简单的实用程序函数帮我代劳:

  1. /**
  2.   * Center one DisplayObject relative to another.
  3.   */
  4. private function center(foreground:DisplayObject,
  5. background:DisplayObject):void
  6. {
  7. foreground.x = (background.width / 2) -
  8. (foreground.width / 2);
  9. foreground.y = (background.height / 2) +
  10. (foreground.height / 2);
  11. }

使用以上 center() 函数进行标题定位很简单:

  1. var title:SimpleLabel = new SimpleLabel("My Application",
  2. "bold", 0xffffff, "_sans", this.inchesToPixels(.15));
  3. this.center(title, titleBar);
  4. this.addChild(title);

最合适内容

为标题栏等动态设置大小和布局是一回事,但实际的应用程序内容可能更具挑战性。例如,主要内容是一个方块网格的游戏。使游戏能在多个设备上运行的最佳技术是什么?方块应当根据屏幕大小缩放,还是应当添加或删除行和列?
对于这个游戏而言,两个方法都有效。 例如,对于棋类游戏或跳棋游戏,不能根据屏幕大小添加或删除行或列。在这种情况下,为了保持一致,最好缩放内容。
有些游戏其实可以根据屏幕大小调整游戏玩法。例如,一款实时战略游戏在较大的屏幕上可以得到增强,因为更高的分辨率可以容纳更多拼贴;如果屏幕较小,最好删除一些拼贴,使剩余的拼贴可以变大并呈现更多细节。在这种情况下,需要调整内容。
为不同的屏幕大小调整内容并没有单一的战略或公式,因为内容各不相同;但可以使用一些标准技术。以下描述根据任何大小的屏幕调整游戏的逻辑:

  • 确定拼贴或块的大小。如果拼贴包含位图,大小由位图的像素维度预定(因为位图在缩放方面不及矢量)。如果拼贴是矢量,您可以决定标准化拼贴的绝对大小。
  • 确定拼贴布局有多少空间。拼贴布局的空间量应当是屏幕总大小减去标题栏、导航等对象的剩余值。
  • 计算将放入剩余空间中的行和列的数量。务必兼顾方块或拼贴之间要留出的间隙。
  • 在可用空间内进行拼贴布局。这比听起来复杂一些,因为棋盘上下总会留下一些空间,您希望将这些空间均匀地分摊到垂直和水平页边距。

以下代码说明了在已分配空间放置尽可能多的 ?" 块,同时在棋盘上下保留相等的页边距:

  1. // Display as many blocks on the screen as will fit
  2. var BLOCK_SIZE:Number = .25;
  3. var BLOCK_BUFFER:uint = 3;
  4. var blockSize:uint = this.inchesToPixels(BLOCK_SIZE);
  5. var blockTotal:uint = blockSize + BLOCK_BUFFER;
  6. var cols:uint = Math.floor(this.stage.stageWidth / blockTotal);
  7. var rows:uint = Math.floor((this.stage.stageHeight -
  8. titleBar.height) / blockTotal);
  9. var blockXStart:uint = (this.stage.stageWidth - ((cols *
  10. blockSize) + ((cols - 1) * BLOCK_BUFFER))) / 2;
  11. var blockX:uint = blockXStart;
  12. var blockY:uint = ((this.stage.stageHeight + titleBar.height) -
  13. ((rows * blockSize) + ((rows - 1) * BLOCK_BUFFER))) / 2;
  14. for (var colIndex:uint = 0; colIndex < rows; ++colIndex)
  15. {
  16. for (var rowIndex:uint = 0; rowIndex < cols; ++rowIndex)
  17. {
  18. // Use a private function to draw the block
  19. var block:Sprite = this.getBlock(blockSize);
  20. block.x = blockX;
  21. block.y = blockY;
  22. this.addChild(block);
  23. blockX += blockTotal;
  24. }
  25. blockY += blockTotal;
  26. blockX = blockXStart;
  27. }
  28. }

以下代码是生成各个块的函数:

  1. /**
  2.   * Get a new block to add to the game board
  3.   */
  4. private function getBlock(blockSize:uint):Sprite
  5. {
  6. var block:Sprite = new Sprite();
  7. block.graphics.beginFill(0xAAC228);
  8. block.graphics.drawRect(0, 0, blockSize, blockSize);
  9. block.graphics.endFill();
  10. block.cacheAsBitmap = true;
  11. return block;
  12. }

注意:创建各个块时,它的 cacheAsBitmap 属性将设置为 true。虽然移动应用程序优化超出了本文的范围,为您没有预料到需要频繁缩放或旋转的 DisplayObjects 将cacheAsBitmap 属性设置为 true 始终是最好的办法。虽然这样可以提高桌面的性能,它可能对处理器能力较弱的设备产生较大影响。

管理字体

字体是几乎所有应用程序的一个重要元素,在对多个屏幕进行设计时,必须像其他资源一样重视它。下面是以跨设备成功调整方式使用字体的三个提示:

  • 使用 FTEFlash 文本引擎):我极力推荐使用 FTE 或 Flash Player 10、Adobe AIR 1.5 和 Flash Lite 4 中引入的全新 Flash 文本引擎。FTE 的渲染效果不仅超过 TextField 对象,它还允许您更精确地放置文本。ascent、descent、textWidth 和 textHeight 等 TextLine 属性使您能以像素级的精确度放置文本。
  • 考虑创建一个组件:在之前的标题示例中,我使用自己的一个名为 SimpleLabel 的简单组件,它内嵌使用了 FTE 并且令文本创建简单许多。我不仅可以在每个要添加一些文本的地方少写几行代码,还可以通过一个中央位置进行通用文本更改或修复文本相关缺陷。
  • 根据需要覆盖 width height getter在我的 SimpleText 组件中,我覆盖了 DisplayObject对象的 width 和 height 属性,使文本字段能与以上 center() 函数等实用程序更好地配合使用。以下是实现最佳效果的 width 和 height getter:

  1. public override function get width():Number
  2. {
  3.    return this.textLine.textWidth;
  4. }
  5.  
  6. public override function get height():Number
  7. {
  8.    return (this.textLine.ascent - 1);
  9.  
  10.  
  11.  
  12. }

后续工作

Flash 开发人员的机会随着 Flash Platform 的增生而增加。使用相同工具、技能和代码跨数量不断增加的各种设备构建应用程序的能力十分强大,并使 Flash 开发人员有机会捕获大量用户。但是,要充分利用 Flash Platform 的普遍性,开发人员需要在构建应用程序时将多个屏幕谨记在心。幸运的是,开发人员只需要理解和掌握少数几个相对简单的技术就可以充分利用 Flash Platform。

关于作者

flex4.5效果:为多个屏幕大小创作移动 Flash 内容 - wolfgangkiefer - 南海群岛

Christian Cantrell

Christian Cantrell 是 Adobe AIR 小组的一名应用程序开发人员。他的工作是通过构建应用程序来验证 AIR API,通过研究新兴技术帮助指导平台方向。阅读他的博客*或通过 Twitter* 了解他的动态。

  评论这张
 
阅读(1264)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017