Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2222914
  • 博文数量: 556
  • 博客积分: 11457
  • 博客等级: 上将
  • 技术积分: 5973
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-24 22:33
文章分类

全部博文(556)

文章存档

2013年(22)

2012年(74)

2011年(460)

分类: 嵌入式

2011-10-01 13:31:46

内容简介

曾几何时,我们Flash开发者的作品只能局限于桌面上的浏览器,而与移动设备基本无缘(您或许还记得Flash Lite,这是当时Flash应用进入移动设备的唯一方式,但是正如其名,这个播放器存在诸多限制,甚至都不支持ActionScript 3.0,所以并没有得到广泛的应用;在Adobe内部,负责这个产品研发的是单独一个团队,并不是Flash Player研发团队,受制于硬件条件等因素,Flash Lite始终只能实现Flash Player功能的一个子集)。自从全功能的Adobe Flash Player和Adobe AIR运行时进入移动设备(这当然要归功于硬件设备的升级和Adobe研发团队的努力),我们Flash开发人员终于等到了这个前所未有的机遇,可以基于我们已经掌握的技能,使用ActionScript 3,来创建一个移动设备项目,或将现有项目迁移到移动设备。

这篇文章要讨论的内容就是,如何让您之前的Flash/ActionScript 3项目,顺利迁移到移动设备。如果您认为只需要将原先的代码打一下包,放到移动设备上运行就行了,那您就把这个问题想的太简单了。实际上,可能我们大部分的代码都可以维持原状,但是因为移动设备的特性,我们需要在界面显示和交互方式等方面进行一些优化,才能比较顺利的在移动设备使用。

前置知识

您需要具备基础的ActionScript 3编程经验,了解如何使用Flash Builder来创建和维护项目;文章涉及的源码以SVN的形式公开,您还需要了解SVN的基本概念和使用方式。

所需软件

您需要下载和安装下面的软件,以便运行这篇文章的相关源码:

  • Flash Builder 4.5 |
引言

这篇文章中总结的观点,实际上是笔者在一个实际项目( FingerChart )上体验而来的。FingerChart是笔者编写的一个开源,轻量级的Flash图表解决方案,基于ActionScript 3编写,可用于AS项目和Flex项目。这个项目在创建之初,主要针对个人PC上的需求,并未专门对移动设备优化,也未在移动设备上进行详细的测试。在前一段时间,抽空检查了一下FingerChart在移动设备上的运行状况,发现还是存在一些问题,遂针对这些问题升级代码,并将这些问题和探索到的解决方式记录下来,和大家分享。

fingerchart

图1 开源Flash图表FingerChart

问题及解决方案

下面是问题以及相关解决方案的列表:

  1. DPI差异导致的UI显示问题

    这个问题非常明显,因为移动设备的DPI值普遍大于PC屏幕的DPI值,导致FingerChart在移动设备上看起来有很多不合适的地方。比如字号,根据PC上的惯例,文本字号设置的是12像素,这个尺寸在PC屏幕上看是没有问题的,但在移动设备的屏幕上看则过于小了,看上去让人感觉很不舒服。

    为什么会产生这个问题?您首先需要了解这个概念。DPI的定义是:每英寸点数,因为在屏幕上一个点实际上就是一个像素,所以我们也可以认为DPI就是每英寸像素数。在PC屏幕上,DPI值基本上都是一致的,但在移动设备上则不是如此,不同的设备之间存在比较大的差异,如下图所示(来自Jason San Jose的文章):

    2

    图2:移动设备的DPI分析图

    DPI值越高的设备,屏幕显示精度越高,视觉效果越细腻(在一些低DPI设备,比如Nokia一些老型号的手机,我们可以非常明显的看到像素点阵;但是在一些高DPI值的设备,比如iPhone4上,则显示效果已经接近于纸质印刷效果),但是对我们造成的困扰是,我们通常基于像素值来确定一个显示对象的大小,这样可能在PC屏幕上显示合适的尺寸,则在高DPI值的屏幕上显得过小。

    举一个例子,假如我们绘制一个图形,尺寸是:72像素*72像素,那么以物理尺寸来衡量,它在电脑屏幕上看起来应该是多大?因为一般我们电脑屏幕的DPI都是72,所以很容易计算出,它在电脑屏幕上看到的物理尺寸就是1英寸*1英寸,换算为厘米则是:2.54厘米*2.54厘米,这个尺寸从视觉来看,应该是我们可以接受的;但假如把它放到iPhone 4上去看,因为iPhone 4的DPI值为326,那么同一个图形在iPhone 4上显示的物理尺寸是多少?通过计算我们可以得知,它的物理尺寸应该是0.22英寸*0.22英寸,即0.56厘米*0.56厘米。您可以看到,显示效果差别是非常大的。

    到这里,您应该已经了解了导致FingerChart显示问题的根源。那么如何解决这个问题呢?我们可以反其道而行之,通过匹配不同的DPI,设置不同的像素尺寸,来达到一致的物理显示尺寸。比如在上面的那个例子中,我们可以在iPhone 4上将图形改为326像素*326像素,那么它的物理显示尺寸正好是1英寸,和我们电脑屏幕上看到的效果是一致的。对于FingerChart来说,也应该采用这样的处理方式,来解决显示的差异问题。

    从图2所示的表格可以看出,如果按绝对的DPI值来衡量,则有太多的情况需要考虑,在实际开发中,如果我们要针对每个不同的值进行优化,无异于一场灾难:执行成本太高昂了。那么如何在显示效果和执行成本上寻找一个平衡点呢?这里我们可以参照Flex 4.5的策略。基于Flex 4.5开发移动应用,同样会遇到DPI的问题,在这里Flex 4.5将DPI值分为3个类别:160,240,320。虽然不同的设备具体的值都是各不相同的,但仔细观察您就会发现,实际上它们都和这三个类别的值的某一个非常接近。就是说,在大部分情况下,我们可以把一个具体的值,舍入到离它最近的一个类别值,这样我们在实际开发中只考虑3种情况就可以,大大降低了开发成本。在Flex项目开发中,我们可以通过Application.applicationDPI来获取这个“映射值”,Flex会自动根据设备的DPI,返回一个最接近的类别值(160,240,或320)。但是在ActionScript项目中,我们只能通过自定义一个方法,来达到相同的目的:

    1. public static function getRuntimeDPI():Number
    2. {
    3. // Arbitrary mapping for Mac OS.
    4. if (Capabilities.os == "Mac OS 10.6.5")
    5. return 320;
    6. if (Capabilities.screenDPI < 200)
    7. return 160;
    8. if (Capabilities.screenDPI <= 280)
    9. return 240;
    10. return 320;
    11. }
    复制代码

    然后我们可以再创建一个方法,根据获得的运行时DPI值和传入的值的初始依赖DPI值的比例,将传入的值换算为一个合适的值:

    1. public static var applicationDPI:Number = 160;
    2. public static function getNumber(value:Number):Number
    3. {
    4. var dpi:Number = getRuntimeDPI();
    5. return value*(dpi/applicationDPI);
    6. }
    复制代码

    这时,我们在设置诸如文本字号,显示对象尺寸的时候,都以设置的applicationDPI为基准(比如上面代码中设置的是160),我们可以认为,我们的初始值都是为DPI是160的设备而准备的。然后我们使用这个值的时候,要用getNumber(yourValue)的方式来获取。这会产生什么作用呢?假如我们的界面设计图是为160DPI而准备的,我们度量出一个按钮的宽度应该是100像素,那么通过这个方法,就可以为不同DPI设备,设置不同的像素值:如果DPI是160的设备,则返回值仍然是100像素;如果DPI是320的设备,则返回值将是200像素,以此类推,我们可以通过这个策略来保证显示对象在不同DPI值的设备上都可以得到优化。如下图所示,FingerChart采用这个策略,优化了文本字号的显示,图中的上半部分是PC屏幕的显示效果,下半部分则是手机屏幕的显示效果:

    3

    图3:物理显示的基本一致

  2. 鼠标事件引起的交互问题

    这是FingerChart遇到的另一个问题。因为移动设备上的交互方式变成了手指的Touch,而不是PC上的Mouse。不过Flash Player还是很人性化的帮我们考虑到了这一点,默认情况下,它会自动转换底层设备的Touch事件为普通的Mouse事件(比如MouseDown,MouseUp),这样一方面降低我们修改代码的成本,一方面方便我们开发阶段的测试。这里我们就需要注意,事件侦听一定要放在PC或移动设备都可以共同使用的事件类型上,比如:MouseDown,MouseUp,Click,MouseMove。而像MouseOver这样的事件,对于移动设备基本是不可用的,所以我们的代码逻辑要尽量避免使用这样的事件类型。

    4

    图4:不同的交互方式

    FingerChart遇到了这个问题,于是将交互方面的代码进行升级,来确保在移动设备上可以顺利交互。

    如果您希望将自己的项目彻底改为移动设备类型的项目,完全用Touch事件来代替Mouse事件,当然也可以,但请思考是否有足够的理由支持您这样做。如果需要这样做,您可以设置Multitouch.inputMode=MultitouchInputMode.TOUCH_POINT;这样您就可以捕获和处理Touch事件。当然这样做额外的好处是,您可以捕获多点触碰事件(如果硬件支持的话),如果您的应用正好需要多点操作的话,那么这么做就变的很有必要。下面这段代码展示了如何使用多点触碰:

    普通浏览复制代码保存代码打印代码
    1. stage.addEventListener(TouchEvent.TOUCH_MOVE,touchHandler);
    2. private function touchHandler(e:TouchEvent):void {
    3.     if(touchDic[e.touchPointID] == null) {
    4.         touchDic[e.touchPointID] = colorCollection[int(Math.random()*4)];
    5.     }
    6.     varrect:Rect= new Rect(touchDic[e.touchPointID]);
    7.     rect.x= e.localX;
    8.     rect.y= e.localY;
    9.     addChild(rect);
    10. }
    stage.addEventListener(TouchEvent.TOUCH_MOVE,touchHandler); private function touchHandler(e:TouchEvent):void { if(touchDic[e.touchPointID] == null) { touchDic[e.touchPointID] = colorCollection[int(Math.random()*4)]; } varrect:Rect= new Rect(touchDic[e.touchPointID]); rect.x= e.localX; rect.y= e.localY; addChild(rect); }
  3. 合理利用手势识别增强交互

    这个实际上不是FingerChart遇到的Bug,而是要实现一个新特性,正好考虑寻找一个在移动设备上最佳的方式。这个特性是基于一个普遍性的需求:对于横轴跨度大的数据,有必要使用数据区间,在PC上我们经常会在Chart底部增加一个可拖动的交互控制区域来实现,如下图所示:

    5

    图5:操控横轴数据区间

    但在移动设备上,无论是屏幕区域的大小限制还是交互操作的困难,都导致上面的方式难以实施。但具备触控屏幕的移动设备,通常是支持手势识别的,我们可以巧妙的利用手势识别,来完成上面所述的交互功能。移动设备通常支持多种手势,包括:滑动,缩放,旋转等等,在这里我们所需要的手势,实际上就是缩放手势。FingerChart判断缩放事件,来对数据区间进行控制。

    代码层面如何实施呢?首先,先设置模式 Multitouch.inputMode=MultitouchInputMode.GESTURE;

    然后我们就可以添加事件侦听: addEventListener(TransformGestureEvent.GESTURE_ZOOM,zoomHandler);在事件侦听器注册的方法里面,就可以通过scaleX获取在横轴方向上的缩放指数,来确定图表的数据区间:

    1. protected function zoomHandler(event:TransformGestureEvent):void
    2. {
    3. var endIndex:int = dataRange[1];
    4. if(event.scaleX < 1)
    5. endIndex+=zoomSpeed;
    6. else
    7. endIndex-=zoomSpeed;
    8. if(endIndex > 0 && endIndex < dataset.collectionPrototype.length)
    9. dataRange = [0,endIndex];
    10. }
    复制代码

    下图展示了在移动设备上通过手势操作FingerChart的情况:

    6

    图6:手势识别

  4. 利用PopUp模式增强用户体验

    在图表中,图例(Legend)是经常使用的一个辅助显示措施,用以说明图表中数据的不同类型。FingerChart也具备显示图例的功能。但是原有Legend(图例)直接放在Chart右上角,在移动设备中难以使用(FingerChart的图例是可交互的,可以控制图形的显示和隐藏)。鉴于移动设备屏幕的有限交互区域,我们决定为移动设备开发专用的图例,将图例改用PopUp的形式弹出,同时增大每一个图例项的尺寸,扩大交互区域,使得在移动设备上易于交互,如下图所示:

    6

    图7:弹出模式

    如果弹出的内容尺寸超出屏幕允许范围,我们还可以使用自定义的滚动容器或列表来进行处理,参加之前的两篇文章:

总结

虽然FingerChart在进入移动设备时,遇到了上面所述的几个麻烦,但实际上解决这些麻烦并没有花费太多时间(这几个问题都是移动设备的特性使然),笔者大概花了2天左右的时间,完成了上面的优化工作,并录制了一个视频,展现FingerChart在移动设备上的表现()。得益于统一的Flash Player平台,FingerChart在核心逻辑保持不变的前提下,通过一些优化工作,顺利进入移动设备。这显然要比用Java或Objective C去为Android或iOS写另一份代码的成本要小太多了。

后续工作

如果您手头正好有一个项目正在以移动设备为目标进行迁移,那么希望这篇文章可以带给您一些启发,您也可以继续浏览Adobe开发者中心,阅读更多关于移动开发的文章。

参考文献:

使用 Adobe Flex 4.5 SDK 和 Flash Builder 4.5 进行移动开发

Flex移动skin – 第2部分:处理不同的像素密度

关于作者

郭少瑞,Adobe认证RIA讲师,Adobe社区专家(ACP),瑞研社区(RIADEV)核心发起人之一,多年来从事RIA技术领域的研发工作,是Adobe Tech Day技术宣讲活动的特邀演讲嘉宾,清华出版社《AIR完整入门与开发实录》作者之一,同时也是开源Flash图表Finger chart作者。

原文地址:http://www.riadev.com/flex-thread-1310-1-1.html

阅读(1366) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

高傲的活着2011-10-01 22:25:16

是的,但是现在是2.5G,未来为了迎接3G,必然带宽、移动设备的带电量不是问题,3G时代必然大家使用手机上网频率高了,这个硬性的东西自然不是问题,不必担心...

zhujiang732011-10-01 13:42:33

Flash 很耗 CPU,也就很耗电,这对移动设备的电池是个考验。