开发基于Flash Player 10.1的Mobile应用经验分享

前几天Adobe公布了针对移动平台的Flash Player 10.1,这个消息想必大家都知道了(如果你还不了解Flash Player 10.1,请参阅这篇文章:Flash Player 10.1为移动设备带来了什么)。这样无论是对传统的桌面Flash应用开发人员,还是移动开发人员,都无疑多了一个选择,即:基于AS3和现有Flash资源积累(素材,第三方类库,开发经验等等),快速开发或移植具备丰富表现力的手机应用。

那么,一个传统的桌面Flash应用开发人员如果进入移动开发领域,应该注意什么事项?或者说,虽然都是基于Flash Player 10.1的开发,但运行于桌面和运行于移动设备的区别在哪里?下面笔者将根据自己的经验和心得写出几点总结,藉以抛砖引玉,欢迎大家讨论。

总体而言,我们在开发针对Flash Player 10.1的移动应用过程中,以往的代码经验和架构还可以继续沿用,没有什么不同,只是要针对移动平台的特殊性,从UI设计,交互方式,和性能优化方面需要做出相关的调整。

1.UI设计与交互方式的差异

这是非常重要的一个方面,移动设备因为平台特殊性,在交互设计方面与普通桌面系统差异很大。如果你的应用没有考虑到这一点,那么后期的修改足以让你疲于奔命。

1.1 屏幕分辨率与UI设计

移动设备的屏幕尺寸一般远小于PC设备,比如Google Nexus One的分辨率是480*800,Motorola Dorid的分辨率是480*854,而且因为都是高分屏(DPI高),所以实际屏幕看起来更小,一般的手机屏幕则大都只有320*480的大小。在如此狭小的区域内,要求你的设计元素必须合理运用,传统的设计思路在这里将不适用。

  1. 尽量减少在屏幕上堆叠内容:将最重要的内容展示出来,不要罗列太多,如果确实需要可以设计为分屏模式。要极尽精简,突出主次,不要多余的装饰。这是移动设备UI设计非常重要的一个特点。
  2. 突出显示可交互内容:包括按钮,链接等等需要交互的元素,必须设计的足够大,才会让用户感觉可以“轻松点击”,因为有过移动设备使用经验的朋友就会知道,用手指在屏幕上是很难精确定位的,所以要求交互元素必须具备很大的响应区域。
  3. 设计图要具备可扩展性:跟网页设计类似,移动设备的UI设计也要考虑分辨率的差异性,在设计中保留可扩展性,比如:可延展的背景,对齐方式等等。

举个例子,下面这张图反映了一个Flash Minisite的设计变更,从开始的复杂设计到最后的简化,明显后面的设计更合理。左边的图很多按钮设计的过小,难以点击。

图1:设计的变更

1.2 Landscape模式

很多移动设备都提供了Landscape模式,即横版模式(将设备翻转90度),这种模式下相当于屏幕的宽度和高度相互调换,那么你的设计是否考虑到了这种变化呢?一旦进入这种模式,或许你需要调整一些UI元素的显示以匹配当前分辨率。

图2 Landscape模式

1.3 移动设备特色的交互

如前所述,移动设备的交互方式和普通PC差异很大,举例来说,对于滚动条(ScrollBar)的使用方式就完全不一样,在普通PC的交互中,比如浏览器,如果网页的实际尺寸超出了显示区域的大小,则浏览器出现一个可交互的滚动条,用户可以通过拖动滚动条导航到需要的位置。但是在移动设备中,因为先天的限制(屏幕尺寸偏小,没有鼠标,难以精确定位),对于超尺寸的显示内容,如果沿袭PC的滚动条处理方式,是难以使用的。所以在移动设备中,一般采用手势(gestrue)来处理这种交互,如下图所示:

图3 对滚动的处理

另外在视图的导航上,移动应用一般也会加入手势的判断,来完成视图的切换(这样一方面符合移动设备用户的操作习惯,减轻操作复杂度,另一方面也节省了放置功能按钮造成的空间拥挤)。在上图所示的应用中,设计为:用户向上或向下拖动视为对超出显示区域的内容的处理(滚动条处理),而用户向左或向右拖动,则视为切换视图,如下图所示(可以想像为在当前显示视图之外排列好了一组视图,可以通过拖动来切换):

图4 视图的切换

你可以进入m.adobe.com体验这种移动设备特色的交互方式。

2.项目编程方面的注意事项

上面我们也提到,既然都是基于Flash Player 10.1和AS3,那么编程方面的差异并不大,我们需要注意的是下面的若干事项:

2.1 自适应分辨率

我们需要考虑使用一种架构,使得界面可以适应各种分辨率,因为我们的项目大多数情况下不能仅限于某一种设备,所以分辨率的差异是无法忽视的。这个时候我们可以借鉴HTML的思路,HTML在这方面做的很好且经验丰富。比如HTML的DIV容器,我们除了可以给它的宽度设置固定的像素值之外,还可以设置百分比,这样它就可以根据父容器的尺寸自我调整尺寸。这种方式在Flex的组件体系中也存在,且得到了加强(比如基于约束的布局,使用left,top,right,bottom和对齐方式等等)。我们可以借鉴这种方式,实现一套微型的布局体系,来适应分辨率的变化。

比如我们实现一种容器,来实现下面的接口设计:

  1. package
  2. {
  3. public interface IContainer
  4. {
  5. function updateDisplayList(...args):void;
  6. function get layout():String;
  7. function set layout(value:String):void;
  8. function get minWidth():int;
  9. function set minWidth(value:int):void;
  10. function get minHeight():int;
  11. function set minHeight(value:int):void;
  12. function get left():String;
  13. function set left(value:String):void;
  14. function get right():String;
  15. function set right(value:String):void;
  16. function get top():String;
  17. function set top(value:String):void;
  18. function get bottom():String;
  19. function set bottom(value:String):void;
  20. function get horizontalCenter():String;
  21. function set horizontalCenter(value:String):void;
  22. function get verticalCenter():String;
  23. function set verticalCenter(value:String):void;
  24. }
  25. }

2.2 慎用复杂动画

虽然目前来看基于Android 2.2的移动设备在处理能力上已经比之前的智能终端强悍了许多,但相比PC处理能力还是非常有限,知道了这一点,我们在应用中如果使用了复杂动画,就要有所斟酌。

  1. 尽量不使用复杂的时间轴动画(包括复杂的遮罩动画),不得以的情况下,有必要使用位图动画代替。
  2. 如果有代码控制的动画(用Tweener或TweenLite),则尽量减少渲染元素,必要时可以使用BitmapData来操作。

2.3 文件合并和优化

手机应用对尺寸优化要求很高,因为手机网络一般较慢,如果应用过大则导致加载缓慢。优化包括:

  1. 优化素材,尽量重用,合理压缩,将单个文件的尺寸降至尽量低。
  2. 减少请求数,必要的话合并文件,因为多文件造成的服务器响应延迟将会拖慢整个加载进度。

2.4 判断手机类型和本地化处理

如果你的应用需要知道访问者的手机类型和语言,那么可以借助服务器端技术(比如PHP)来加以判断。在HTTP请求的Header区域,有一个User-Agent值,记载了终端的信息,你可以从这里拿到需要的信息。

  1. <?php
  2. foreach (getallheaders() as $name => $value) {
  3. if($name == 'User-Agent') $userAgent = $value;
  4. }
  5. ?>

2.5 鼠标事件和手势

在移动设备中的开发中,我们很少使用MouseEvent.CLICK,而是采用MouseEvent.MOUSE_DOWN,MouseEvent.MOUSE_UP,以及MouseEvent.MOUSE_MOVE的组合来实现对点击区域的判断,和手势(拖动,滑动等等)。注意MouseEvent.MOUSE_OVER和MouseEvent.MOUSE_OUT在这里将完全无用武之地。

一个在移动设备中使用鼠标事件的例子:

  1. package
  2. {
  3. import flash.display.Sprite;
  4. import flash.display.StageAlign;
  5. import flash.display.StageScaleMode;
  6. import flash.events.Event;
  7. import flash.events.KeyboardEvent;
  8. import flash.events.MouseEvent;
  9. import flash.geom.Point;
  10.  
  11. /**
  12. * 测试类,测试移动设备上的点击操作
  13. * @author NeoGuo
  14. *
  15. */
  16. public class TouchTest extends Sprite
  17. {
  18. private var drawStats:Boolean = false;
  19. private var canvas:Sprite = new Sprite();
  20. private var startPoint:Point = new Point();
  21. private var clickStats:Boolean = false;
  22.  
  23. public function TouchTest()
  24. {
  25. stage.align = StageAlign.TOP_LEFT;
  26. stage.scaleMode = StageScaleMode.NO_SCALE;
  27.  
  28. canvas.doubleClickEnabled = true;
  29. this.graphics.beginFill(0xFFFFFF,1);
  30. this.graphics.drawRect(0,0,stage.stageWidth,stage.stageHeight);
  31. this.graphics.endFill();
  32.  
  33. stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseHandler);
  34. stage.addEventListener(MouseEvent.MOUSE_MOVE,mouseHandler);
  35. stage.addEventListener(MouseEvent.MOUSE_UP,mouseHandler);
  36. stage.addEventListener("touchClick",addPoint);
  37. stage.addEventListener(KeyboardEvent.KEY_DOWN,clear);
  38.  
  39. addChild(canvas);
  40. }
  41.  
  42. protected function mouseHandler(e:MouseEvent):void {
  43. if(e.type == MouseEvent.MOUSE_DOWN) {
  44. drawStats = true;
  45. clickStats = true;
  46. startPoint.x = mouseX;
  47. startPoint.y = mouseY;
  48. } else if(e.type == MouseEvent.MOUSE_UP) {
  49. drawStats = false;
  50. if(clickStats) {
  51. trace(clickStats);
  52. stage.dispatchEvent(new Event("touchClick"));
  53. }
  54. } else if(e.type == MouseEvent.MOUSE_MOVE) {
  55. clickStats = false;
  56. drawLine();
  57. }
  58. }
  59.  
  60. protected function drawLine():void {
  61. if(!drawStats) return;
  62. canvas.graphics.lineStyle(3,0x000000,0.5);
  63. canvas.graphics.moveTo(startPoint.x,startPoint.y);
  64. canvas.graphics.lineTo(mouseX,mouseY);
  65. startPoint.x = mouseX;
  66. startPoint.y = mouseY;
  67. }
  68.  
  69. protected function addPoint(e:Event):void {
  70. var p:DemoPoint = new DemoPoint();
  71. p.x = mouseX;
  72. p.y = mouseY;
  73. canvas.addChild(p);
  74. }
  75.  
  76. private function clear(e:Event):void {
  77. canvas.graphics.clear();
  78. while(canvas.numChildren!=0) {
  79. canvas.removeChildAt(0);
  80. }
  81. }
  82.  
  83. }
  84. }
  85. import flash.display.Sprite;
  86.  
  87. class DemoPoint extends Sprite {
  88. public function DemoPoint() {
  89. this.graphics.beginFill(0xFF0000,0.5);
  90. this.graphics.drawCircle(0,0,10);
  91. this.graphics.endFill();
  92. }
  93. }

(未完待续)

您给予的分值: None 平均分: 9.3 ( 6 票)

CNET是用Flash做的吗

你好,
这个文章图片的CNET,是因为他是用Flash做的移动引用吗
http://www.cnet.com/
看似很不是为移动设备优化的,很奇怪啊。

另外,人机交互还是要看苹果和谷歌的指导吧
http://developer.apple.com/iphone/library/documentation/userexperience/c...
http://developer.android.com/guide/practices/ui_guidelines/
作者不是做移动应用的吧

你好 cnet图片是m.flash.c

你好
cnet图片是m.flash.com中的一个范例,需要用手机进入才能看到。

另外,这个文章中作者也说了,是要抛砖引玉,这里希望给大家使用Flash设计移动引用一些意见。
当然,文中提到的两个连接的确是值得学习和参考的。

谢谢提供

分辨率这个问题的确麻烦

分辨率是480*800 这个其实不小了。
都比现在那些平板电脑高了吧。

为什么Flash专门给触摸设备的那些事件不能使用呢

可以用专门为触摸设备做的那些事件吧。
我想问为什么楼主不用那些事件,那样不是省很多事情吗

因为Touch和Gesture在官

因为Touch和Gesture在官方的FAQ里说,目前还不能支持移动设备。

麻烦问下

"因为Touch和Gesture在官方的FAQ里说,目前还不能支持移动设备"
这是在哪个FAQ里面说到的。。麻烦能否告知下

发表新评论

  • 网页地址和电子邮件地址将会被自动转换为链接。
  • 行和段被自动切分。
  • 您可以使用下面的标签来高亮显示您的评论内容: <code>, <blockcode>. 可以使用"[foo]".旁边显示标签样式 "<foo>" PHP代码可以用这样的区块来包含<?php ... ?> or <% ... %>

更多格式化选项信息

验证区域
系统验证:请回答下面的问题