ADC推荐:手机屏幕触控技术与提升AIR在Android上的触控体验

本文由ADC中文站推荐

生日那天给自己买了个iPad,今天又添了个华为的3G无线热点,加上手里的HTC,家里的三个笔记本和一个台式机,我现在已经被完全包围在电子产品的辐射之中。远观书房里的那个台式机,近看iPad和HTC,前后相差也就4年多,我不禁感慨现在的科技怎么更新的这么快⋯⋯

感慨完了是本文的正题,现在无键盘智能手机和平板电脑正在迅速走进我们的生活,触控这一最直接有效的交互方式正在悄悄颠覆着传统的交互设计模式。我今天要先对手机屏幕的触控技术做一个简单的介绍,然后在另一端,从应用的层面来分析触控体验的优化。

要求

范例文件:

手机屏幕触控技术

现在的触控屏都是电容屏,特点就是它会跟你的手指头相互放电,然后根据在玻璃屏的传感器上产生的电容耦合计算出触点。与传统的电阻屏相比,电容屏的好处就是不用使劲儿按,比较温柔。目前的电容屏技术主要分为自我电容(Self Capacitance)和交互电容(Mutual Capacitance)两种。

自我电容的原理很简单,传感器上有两块板,一块板代表一个轴,手指头一碰,两个轴都会有一条感应线,两条线相交的点便是触点。我的HTC Desire和7yue的Nexus One都是用的这样的触摸屏,也就是Synapitics的ClearPad 2000。自我电容触控技术有一个最大的缺点,就是只能处理两根手指头的手势,而不能作多根手指头的多点计算。原因就是如果当你按下两根手指头,在两个传感轴上就会各有两条感应线,四条线相交就是四个点,其中两个点是你按的,另外两个不是,所以传感器就无法判断哪两个点是假的(如下左图)。解决办法有一个,增加一层传感轴。这样,在三个轴六条线的八个交点中只有你按的那两个点是三条线的交点,所以三层传感轴可以判断两个点。同样,四层传感轴可以判断三个点,五层可以判断四个点⋯⋯ 如果用这种技术来判断我们的十根手指头,那么手机最后需要做得像砖头一样厚。但是用自我电容作手势识别很容易,计算旋转缩放的效率很高。

另外一种电容屏用的是交互电容技术,原理也不难。传感器上还是有两块板,同样代表两个相互垂直的轴,手指头一碰,只在一个轴上有一条感应线,然后从另一个轴发出一条扫描线,扫描线和感应线一相交就能算出触点(如下右图)。用这样的技术,就算你按上20根手指头,产生20条感应线,也同样会被一一扫描出来。但是这种扫描技术很耗费处理器,比如iPhone和iPad都是用的这种屏,iPhone就用了两块独立的处理器,一个用来计算触点,一个用来计算手势。

传感器上的触点

1.传感器上的触点

这几天炒得沸沸扬扬的谷歌最新的Android 2.3操作系统,首先搭载在Samsung Galaxy S手机上问世,这款手机的触控屏是ATMEL的maxTouch系列,型号mXT224,在交互电容技术基础上增加了AVR微控制器,据说可提供无限的触摸功能、最快的响应时间。从参数表上看非常的诱人,但本人没有亲自测试过,所以不知道是啥体验。

但无论是什么样的传感器,无论有多快的响应时间,从手指头到屏幕,从屏幕到手机系统,从手机系统到操作系统,从操作系统到应用,从应用再到屏幕刷新,这一连串儿的过程决定了它怎么着也不如你用手在地上搬石子儿流畅。所以触控的体验在将来无论是硬件还是软件,无论是系统还是应用都大有优化的空间。

我这里有一个AIR的例子,对于AIR应用来说,应用程序与操作系统之间更多了一层AIR运行时,可以说可以优化的空间更大。虽然这个例子目前的结果与我的初衷相比还差得远,但至少可以证明在最前端的程序阶段也是可以做一些事情来提升整体的触控体验。

提升AIR应用的触控体验

从手指碰到屏幕的那一刻起,我们就期待着手机会当即作出反应。可是由于传感器的捕捉,处理器的运算以及表层应用的运行效率等等因素,手指的运动和应用程序所作出的响应总是有一个时间间隔。另外,屏幕的刷新率也影响着触控的体验是否自然流畅。作为前端开发者,我们是无法提升硬件和系统的性能,但是我们可以想办法通过代码从应用的这个层面提升体验。

从Flash Player 10.1和AIR 2.0开始ActionScript里有了一套控制触控事件的API。如下面这个例子:

  1. import flash.event.TouchEvent;
  2. import flash.ui.Multitouch;
  3. import flash.ui.MultitouchInputMode;
  4.  
  5. Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
  6. mySprite.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);
  7. function touchBeginHandler(pEvent:TouchEvent):void{
  8. mySprite.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler);
  9. mySprite.addEventListener(TouchEvent.TOUCH_END, touchEndHandler);
  10. }
  11. function touchMoveHandler(pEvent:TouchEvent):void{
  12. /**UPDATE MOVE ACTIONS HERE**
  13.   }
  14.  
  15.   function touchEndHandler(pEvent:TouchEvent):void{
  16.   mySprite.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler);
  17.   mySprite.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler);
  18.   }

TouchEvent是用来响应可以用触摸来交互的设备如手机,平板,笔记本电脑等。它的用法与MouseEvent类似,不同的是TouchEvent多了pressure和touchPointID等针对触摸设备和多点触控的API。这里我们不说多点触控,只用它来写一个简单的菜单拖放控制程序,如下:

  1. import flash.event.TouchEvent;
  2. import flash.ui.Multitouch;
  3. import flash.ui.MultitouchInputMode;
  4.  
  5. var startX:Number;
  6. var endX:Number;
  7.  
  8. Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
  9. mySprite.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);
  10.  
  11. function touchBeginHandler(pEvent:TouchEvent):void{
  12. mySprite.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler);
  13. mySprite.addEventListener(TouchEvent.TOUCH_END, touchEndHandler);
  14. startX = pEvent.stageX;
  15. }
  16. function touchMoveHandler(pEvent:TouchEvent):void{
  17. endX = pEvent.stageX;
  18. myMenu.x += endX - startX;
  19. startX = endX;
  20. }
  21. function touchEndHandler(pEvent:TouchEvent):void{
  22. mySprite.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler);
  23. mySprite.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler);
  24. }

上面是我们通常用的代码,放在电脑里运行没有问题,但如果用同样的方法运行在手机上,刚才我们所提到的延迟就会非常明显。如下图,手指按在绿色方框的中心然后往右拖动,由于延迟响应,绿色方框在移动的过程中会一直"落后"。

手机上的响应延迟

2.手机上的响应延迟

如果我们对这段代码稍加改动,让菜单在开始移动的时候迅速移动,移动的速度大于手指的移动速度,在移动过程中速度递减最后等于手指的移动速度,使得绿色方框在经过短暂的落后之后赶了上来,这样就会从视觉上感觉整体运动流畅一些。代码和示意图如下:

  1. import flash.event.TouchEvent;
  2. import flash.ui.Multitouch;
  3. import flash.ui.MultitouchInputMode;
  4.  
  5. var startX:Number;
  6. var endX:Number;
  7. var speed:Number;
  8. var offset:Number;
  9.  
  10. Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
  11. mySprite.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);
  12.  
  13. function touchBeginHandler(pEvent:TouchEvent):void{
  14. mySprite.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler);
  15. mySprite.addEventListener(TouchEvent.TOUCH_END, touchEndHandler);
  16. startX = pEvent.stageX;
  17. offset = 1.5;
  18. }
  19. function touchMoveHandler(pEvent:TouchEvent):void{
  20. endX = pEvent.stageX;
  21. myMenu.x += (endX - startX) * offset;
  22. offset *=.95;
  23. offset = Math.max(offset,1);
  24. startX = endX;
  25. }
  26. function touchEndHandler(pEvent:TouchEvent):void{
  27. mySprite.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler);
  28. mySprite.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler);
  29. }

改进后的响应速度

3.改进后的响应速度

考虑到手指来回移动的情况,则每次移动方向发生改变的时候都要让offset重置,这样菜单才会快速跟紧手指。另外,当菜单移动到边界的时候,菜单的停止不应该是生硬地嘎然而止,而应该是缓慢而有弹性的运动。所以我添加了一些额外的代码,写成下面的这个例子,大家可以下载并在你的手机上测试。值得一提的是,在发布设置中将渲染模式选为GPU,可以让移动更加流畅。

我在这个例子里尝试过其他的一些方法。比如一种智能推测,也就是每次移动的时候让菜单根据手指的当前速度(当然这个速度相对手指来说已经延迟了)推算下一个时刻手指可能移动的位置,用这种方法来抵消传感器信号的延迟。可是效果很不好,尤其是当手指的运动速度发生较大的变化时,菜单的运动就会失真的厉害。我相信一定会有更好的方法从程序的层面解决或者优化这个问题,希望对此感兴趣的朋友一起来研究。

关于作者

James Li

李鹏(James Li),2001年毕业于吉林大学商学院,同年接触Photoshop,Illustrator和Flash。毕业后一直在从事Flash的设计与开发,在教育、IT、互联网广告等不同领域里做过4年的Flash设计师和5年的RIA程序开发,期间曾在2006与2008年两次去德国工作,对Flash前端交互设计有独到的见解和丰富的经验。

ADC中文站原文地址: http://www.adobe.com/cn/devnet/air/articles/improve_exp_andriod.html

riadevID: 
您给予的分值: None 平均分: 5.4 ( 189 票)

发表新评论

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

更多格式化选项信息

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