2009年11月24日星期二

编写 iPhone Friendly 的 Web 应用程序 (Part 7 - 多点触击)

这个系列的上一篇文章差不多是两年之前的事情了,在这两年里Mobile Safari并非停滞不前,从iPhone 2.0开始Mobile Safari就加入了对多点触击的支持,现在我们就来看一下我们可以利用它来干什么。

相信很多人都看过WPF为Surface设备做的一个简单demo,也就是在桌面上显示若干张照片,你可以通过单点触击拖放,也可以通过多点触击缩放和旋转。这在iPhone上能够做到,甚至在Mobile Safari里面也能做到,因为Mobile Safari提供了一套专门用于多点触击的JavaScript接口。现在我们就来看看如何利用这套接口吧。

我们都知道,Mobile Safari自身会处理多点触击,默认行为包括滚动和缩放。我们可以接管相应的事件,同时使用e.preventDefault()禁用浏览器默认行为,使得我们的Web应用程序能够如同WPF桌面应用一样处理多点触击。下面我们来深入看看Mobile Safari提供的多点触击事件。

单点触击

首先我们要处理的是单点触击事件,禁用浏览器的滚动行为,同时为我们的照片(一个img元素)增加拖动行为。在这里,我们需要用到touchstarttouchmovetouchend事件。在这三个事件里,我们可以通过e.targetTouches获取到用户点击的坐标,从而计算相对的位置变化。

首先,我们要在touchstart事件里面记录下初始坐标:

var transform = {
  x: 0,
  y: 0,
  rotation: 0,
  scale: 1
};

var startX;
var startY;
var touching = false;

element.addEventListener("touchstart", function(e){
  e.preventDefault();
  startX = e.targetTouches[0].clientX;
  startY = e.targetTouches[0].clientY;
  touching = true;
});


接着,我们要在touchmove事件里面计算相对位置变化,并且更新element坐标:

element.addEventListener("touchmove", function(e){
  e.preventDefault();
  if (!touching) return;
  transform.x += e.targetTouches[0].clientX - startX;
  transform.y += e.targetTouches[0].clientY - startY;
  updateTransform();
  startX = e.targetTouches[0].clientX;
  startY = e.targetTouches[0].clientY;
});
updateTransform做了什么?现在先不讨论,我们只要把事件相关数据正确地更新到transform的四个属性即可,如何把这些属性反映到界面上稍后再说。

最后,我们还要在touchend事件里面处理一下标志位:

element.addEventListener("touchend", function(e){
  e.preventDefault();
  touching = false;
)};


就这么简单?是的。关键点也就在于touchmove时跟踪e.targetTouches的变化,并更新transform里面的信息。

CSS3变换

接下来我们看看如何将transform里面的信息作用到界面上。在没有CSS3的时代,这是极之痛苦的事情,我们需要修改元素的多个样式属性才能实现这部分的功能,并且还没办法实现旋转。现在有了CSS3,只需要修改一下transform属性就可以了:

var updateTransform = function(){
  element.style.webkitTransform
    = "translate(" + transform.x + "px, "
    + transform.y + "px) "
    + "rotate(" + transform.rotation + "deg) "
    + "scale(" + transform.scale + ")";
}


一句代码就把位置、旋转、缩放都设置好了!尽管我们现在还没用到旋转和缩放属性,那就让它们保持默认值吧,我们在多点触击的事件里面会设置它们的。

多点触击

多点触击涉及到三个事件:gesturestartgesturechangegestureend。这三个事件跟单点触击的三个事件非常类似,使用起来甚至可以说是更简单一些:

var startRotation;
var startScale
var gesturing = false;

element.addEventListener("gesturestart", function(e){
  e.preventDefault();
  startRotation = transform.rotation;
  startScale = transform.scale;
  gesturing = true;
});

element.addEventListener("gesturechange", function(e){
  e.preventDefault();
  if (!gesturing) return;
  transform.rotation = startRotation + e.rotation;
  transform.scale = startScale * e.scale;
  updateTransform();
});

element.addEventListener("gestureend", function(e){
  e.preventDefault();
  gesturing = false;
});


代码确实比之前的还要少一些,重点就是正确设置transform的两个属性,随后调用一下updateTransform就能把最近的状态更新的界面上。

小结

在这篇文章里,我们了解到了Mobile Safari的6个特有事件,以及如何利用这6个特有事件处理多点触击。

如果你直接使用我的代码去实现开头所说的照片拖放应用,你会发现一个小问题——在进行多点触击操作时,旋转与缩放都是很自然的,就是拖动不自然,好像拖动只跟随第一个触点似的。原因很简单,在多点触击时,管理触点移动的还是touchmove事件,但上述代码只处理e.targetTouches[0],所以拖动只跟随第一个触点。

如果需要同时跟随两个触点,你需要对代码稍作改动,使得移动距离为e.targetTouches[0]e.targetTouches[1]的平均值。为什么呢?如果一个触点往上移动30px,另一个触点往下移动10px,除去旋转与缩放效果外,照片的中点应该是往上移动10px的,也就是两个移动的平均值。那么我如何知道当前有多少个触点呢?看看e.targetTouches.length就知道了。

最后,如果你关注移动设备上的Web开发,欢迎订阅我的博客:

2009年11月23日星期一

不看《时尚先生》的你竟然看《程序员》?!

我的博客订户有多少人看《时尚先生》的,举手来看看?博客园里又有多少人是看《时尚先生》的,喊出来听听?我相信绝大多数程序员都是不看《时尚先生》的,尽管它定位为男性杂志,但不看的人不会因此而觉得自己不够男人,也不会去指责一本男性杂志的编辑为何不考虑男性程序员。(为了表示我没有性别歧视的倾向,请女程序员自行将本文的《时尚先生》替换为《时尚》,将Esquire替换成Cosmopolitan。)我们都明白一个道理,一本男性杂志的目标受众往往只是一小部分的男性而已,自己不属于这个群体并不是什么大不了的事情。我相信包包也懂这个道理,只是他没有尝试用同样的思维方式去理解《程序员》而已。

Looking into commons between these two magazines.
2009年11月的《程序员》(感谢CSDN赠送)与《时尚先生》

在我眼里,《程序员》和《时尚先生》是目标受众不同但定位相似的两本杂志。《时尚先生》中国内地版遇到的问题(相对美国版的Esquire而言),《程序员》或多或少地也会遇到。

谁为杂志买单?

你上街买份¥1的报纸,搞不好还送你一瓶水,你觉得这份报纸的制作成本是谁买单的?难道是你买单的?除非你想着的是,报纸是国有的,国家是人民的,你也有一份。准确来说,你在报摊看到的各种报刊杂志都是由广告主买单的,你支付的价格只是个象征性收费,这些钱根本不足以回本,没有广告主也就没有这些报刊杂志。因此,一本杂志要活下来,首先要有广告主为它的生存买单。

广告主为何要为《程序员》的生存买单?肯定是因为广告主能够有所收益嘛,例如说使得读者购买广告主的商品,或者是使得读者试用广告主的服务,也可能是为广告主建立特定的品牌形象。无论如何,《程序员》总得为广告主带来收益,否则广告主没理由要养着它。

现在设想一下,假如你是广告主,你选择投放广告到Google还是Baidu?当然是哪个效果好投放到哪个啊!Anders Liu提到《程序员》曾经还有两个兄弟叫做《CSDN开发高手》和《MSDN开发精选》。假如你是广告主,你要在这三本杂志中选一本投放广告,你会如何作出选择?我想答案还是一样的,哪本的投放效果好就投哪本。

《程序员》上面曾经有过Visual Studio、DB2的广告,也曾经有过不少控件组件的广告。然而,作为程序员的你是否真的有购买过Visual Studio、DB2以及第三方控件组件,又或者建议公司购买?我想绝大多数程序员都不会选择个人购买,建议公司购买的也甚少。因此,无论《程序员》能够覆盖到多少真正的程序员,都不能为广告主带来真正的价值。与其将发行量浪费在购买力低下的程序员身上,不如直接瞄准有权左右公司购买行为的高管。

回到刚才的问题,如果摆在面前的是面向高管的《程序员》和面向程序员的《CSDN开发高手》和《MSDN开发精选》,作为广告主的你会怎样选择?答案应该简单得不能再简单了吧。

杂志做给谁看?

《时尚先生》是做给哪些男性看的?当然是做给有购买力的男性看的,否则为何能有那么多的广告主愿意向它投放汽车服饰广告,没有这些广告又如何支撑起一本杂志的制作成本。《程序员》是做个哪些程序员看的?当然是做给有购买力的程序员看的,道理是类似的,我就不再复述了。

那么到底哪些程序员有购买力?有购买力的前提是有可供支配的资金,这既可能是公有的,也可能是私有的。例如说,假设你能够影响公司的采购策略,服务器选用HP还是Dell,个人桌面选用Windows、Linux还是Mac,开发平台选择.NET还是Java,那么你就是有购买力的,《程序员》也就是做给你看的。这也正是《程序员》现在瞄准的市场。

相对来说,私有财产的购买力是无法跟公有财产比的。你不可能指望程序员个人去购买Visual Studio,你甚至不能指望程序员个人去购买控件,程序员在职业发展方面的消费通常也就覆盖到图书市场,偶尔有人好像Jeff这样的会买Kindle和原版书,也有少数人会自费参加一些行业性大会。

在这里面有一个有趣的现象,程序员收入越高越不需要把自己的收入投入到职业发展里面去,因为高收入的程序员都在大公司的重要岗位上,公司都愿意为他们的职业发展做投资。因此,说到底,与程序员职业相关的各项支出大多由公司支付,Windows服务器是公司买的,Visual Studio也是公司买的,去参加TechEd的门票是公司买的,书架上的那本《代码大全》也是公司买的。

综上所述,《程序员》就是做给那些决定怎么把公司的钱花掉的人看的。如果你不属于这部分人,你是否阅读《程序员》,阅读之后有什么想法,都不会对杂志本身产生什么实质性影响。

杂志为谁而做?

Andres Liu说《程序员》借人物提高知名度,同时也帮助人物提高知名度,这个模式就跟时尚杂志一样嘛。李开复登上《时尚先生》封面,对谁有利?当然是对双方都有利啊——李开复在这个时候需要出镜来促进自己的新事业,《时尚先生》也需要这个话题来满足读者的需求,甚至吸引潜在读者中的李开复粉丝。

举个更遥远的例子,Playboy也是采用同样的模式,所以才有那么多名人愿意接受采访,所以才有那么多美女愿意接受拍摄,自然Playboy本身也很出名。你看到Playboy上的美女,会觉得她们是在沽名钓誉吗?你根本就不在乎这是不是沽名钓誉,你在乎的只是美女本身。因此,如果包包觉得《程序员》上的人物都是为了沽名钓誉,这只能怪他自己没站对角度来看问题。站在看美女的角度来看这些人物,他们是否沽名钓誉与我有何关系呢?

我相信,美国的电视电影导演不会在乎美女上Playboy是否为了沽名钓誉,能通过试镜的都是合适的演员,Playboy只是提供了一种第三方认可外加选拔来源而已。我也相信,中国的公司不会在乎程序员上《程序员》是否为了沽名钓誉,能通过面试的都是合格的员工,《程序员》的作用自然是和Playboy一样。

小结

为什么我选择在包包跟Andres Liu的争论过后那么久还来讨论这件事?我只是希望大家明白,看待问题的角度是多种多样的。程序员往往比较理想化,因为代码总能按照理论的方式运作,但把这种理想化套在《程序员》的真实运作上就不可行了,或者套在一些更复杂的商业场景上就很容易出错。

举个例子,你觉得CCTV为什么喜欢曝光Baidu和Google的搜索结果问题呢?有很多人很单纯地认为,在竞争对手之间,一方受损肯定使得另外一方获利,因为这是个零和竞争。但在这不是一个封闭的零和竞争,把视觉锁定在这样一个竞争之内得出的结论不一定是对的。不信?我可以提供一些信息来拓宽你的思路。国内的传统媒体都喜欢负面新闻,当别人陷入公关危机的时候,就打个电话给对方的公关部门,“我们已经写好了整版你们的负面新闻准备付印,你们有计划增加明年的广告预算吗?”这使得一些公司投放广告只是为了跟媒体建立共同利益关系,限制媒体无法作出伤害自己的行为,否则媒体自己也会受到伤害(我营收减少股价下跌还哪有那么多广告预算给你)。

尝试换个角度看问题,你自然能够得出不同的结论。在你想要对一个你觉得很简单的问题下定论的时候,为什么不尝试换个角度再看看呢?

2009年11月17日星期二

我在 TechEd 2009 演讲的资源 (Silverlight & Ajax)

这是TechEd第二天下午的Silverlight课程资源。关于百度Hi的Silverlight实现方面的任何问题,都欢迎与我讨论。



这是TechEd第三天下午ASP.NET 4课程资源。与ASP.NET AJAX 4.0相关的问题可以在此讨论。

User Friendly 2009

这个周末有幸去上海参加了UPA China组织的用户体验行业大会User Friendly 2009。参会人员大多数都是设计师,会议内容也是他们熟悉的内容,但对于像我这样少数的参会工程师来说,这样的会议确实让人大开眼界。

在整场会议当中,我觉得让我印象最深刻的就是Jared M. Spool的Keynote了,我觉得其中一些观点是非常有价值的。至于其它的Workshop,也都能学到一些实实在在的东西,不过就没有Keynote那么震撼了。下面就分享一些我印象最深刻的内容:

从ROI到ROX

Jared M. Spool的Keynote标题为The Dawning of the Age of Experience(体验时代的来临)。这跟我们传统所说的产品设计有什么不同?那就是我们需要把视觉从产品放大到体验上来。在这里,我想借用MIX 09上Bill Buxton的Keynote中的几页幻灯片来解释一下:

Day One Keynote hosted by Ember

Bill Buxton有一辆这个型号的自行车,而且这也正是Roland Green获得公路赛冠军所用的自行车型号。画面上给你传达的是这辆自行车相关的信息,但又如何?这世界上还有千万款不同的自行车,为什么要在乎这特定的一辆?这不是人们想要购买的东西。

Day One Keynote hosted by Ember

这张幻灯片是同一辆自行车的不同摆放方式,就像是Pixar动画短片里面的那个独轮车一样。这赋予了它一定的个性,这个思路是对的,但这仍然不是你想要购买的东西。

Day One Keynote hosted by Ember

这才是体验设计师应该关注的事情——你骑着车从山上沿着小径冲下来,一直冲到溪谷里,伴随着你的尖叫水花四溅。这是一辆什么型号的自行车?从画面上看不出来。这是一辆什么牌子的自行车?也说不清楚。这从根本上就和自行没有关系,真正有关系的是你尖叫着冲进小溪里的那种刺激的体验。

过往我们谈论的是投资回报(ROI),现在我们谈论的是体验回报(ROX)。我们想要向用户推销我们的产品,但实际上他们想要从我们这里购买体验,因此我们必须改变思维方式,考虑向用户提供什么样的体验。

举个例子,用户在你的网站上购买机票,他想要买的其实不是机票这样一个商品,而是一趟舒适的商务旅行。因此,过往只卖机票的网站开始加上酒店服务。在你输入往返日期后,不仅仅搜索往返机票,还搜索目的地的酒店信息。只有我们向用户提供符合他们预期的体验时,我们才能够获取到高回报。

Chicken Sexer的故事

什么是Chicken Sexer?就是一些判断小鸡性别的专业人员,他们盯着眼前一群两星期大的小鸡,就能指出每一只是公的还是母的,精确率最高可达97%!你让他们说说经验,他们也可以归纳出一些来,例如根据毛色、屁股来判断小鸡性别,但这些规则对于外行人来说一点意义都没有,你实在无法看着一只小鸡然后利用这些规则判断出它的性别。

那么Chicken Sexer是如何练成的呢?新人必须跟着一位大师一起工作,新人负责指出小鸡性别,说错了大师就狠狠地打一下新人的手臂。在接受训练之前,任何正常人都有 50%的正确率;在开始接受训练之后,新人的正确率会先下跌到40%——因为他想得太多了。三个月后,正确率会慢慢恢复到50%,一年之后,你的正确率能够提高到60%;再过两三年,你的正确率能够提高到80%。如果你真的把这当作你毕生的事业来做,正确率可以提升到95%。

Jared M. Spool对这个故事的总结是,有些事情是可以学习而无法自省(introspection)的。在这里,“自省”是指对自身心智或情感变化的观察和检验。设计工作也属于可以学习无法自省——你可以通过学习让自己的设计能力获得提升,但你无法归纳出你在学习过程中发生了哪些变化,以便让其他人直接通过同样的变化以获得同样的结果。

我对这类技能的学习方法看法是,你必须在大师级人物的指导下学习,你才能成为大师。这不是任何人能够通过理论知识的学习或者基础技能的训练就能习得的,这些只能让你胜任需要这些技能的工作,但不能让你成为大师。在你成为大师后,你也无法将你的技能归纳为一组理论,你只能通过亲自训练让更多人习得跟你一样的技能。

企业内推广的两个关键

在Tencent CDC的统一体验的设计Workshop上,我了解到了在企业内推广统一体验的两个关键:老板和项目。

首先,需要老板重视这件事情。例如在Tencent内部,马化腾相当于“首席体验官”的角色,他重视这个事情,对于做得不好的他会站出来指责,别人自然愿意接受你要推广的,因为没有谁想被老板指责。其次,需要通过有价值的项目来证实你推广的东西。如果你的东西你应用于QQ,对其它Tencent产品来说自然就有说服力了。

上述就是User Friendly 2009对我最有启发的几点。如果你对此类会议的信息有兴趣,欢迎订阅我的博客:

2009年11月16日星期一

Tech·Ed 2009

今年是我第一次以讲师身份参加TechEd,碰巧TechEd所在的周末我们要搬家到百度大厦,所以我星期四早上搞掂打包工作后就赶到了会场。凭着《讲师指南》进入会场后,我直奔讲师休息室领取证件和衣服,然后再跑到MVP站台领取印章,接着等待第一天下午的Keynote开始。

尽管我没有参加Windows 7 Launch而跑去参加SD2C了,但我仍然觉得第一天Keynote的一半是Windows 7 Launch的重播。至于Keynote的另外一半,则是与Windows 7并列于New Efficiency系列的Windows Server 2008 R2以及Exchange Server 2010。我认为比较有趣的是Exchange Server 2010的演示,这个演示通过丢失笔记本电脑的场景来说明虚拟桌面的强大——换一台电脑,同一个桌面;这个演示还通过丢失手机的场景来说明远程擦除手机数据的特性。没错,这些功能都很好,但我个人的观点是——如果你经常丢失手机和电脑,Exchange Server 2010的价值才会被凸显出来。最后,我觉得Exchange Server 2010最有价值的功能就是内置的VoIP了,这相当于内置了一个Google Voice,搭配Outlook 2010的邮件视图,你就可以在自己的企业内享受全套的Gmail + Google Voice体验了。

Keynote之后的是面向Microsoft员工和讲师的Welcome Dinner,也是难得的交流时间——白天大家都忙于会务、讲课、停课,晚上才有时间停下来聊聊技术。当看到有人说自己讲了十年TechEd之后,就如同看到Rick Strahl博客上的的“MVP since 1997”一样震撼——原来有人一直在做这样的事情,并且坚持了10年之久。有兴趣有动力去做好一件事情不难,难就难在坚持做10年。

第二天上午我抽空去郭晓颖的Session上听了一下她是怎么讲Silverlight的,顺便在她的Q&A环节为自己的Session卖了一下广告。其余时间,我都在忙于调整我自己的pptx,直到下午我的Session开始为止。在Session结束后,我又花了一些时间解答大家的问题,以及帮大家盖MVP的章,然后才赶往Jeff的Session听他讲MVC。

第二天晚上是MVP Dinner,很高兴又能跟一群MVP朋友聚会了。为什么MVP Dinner有价值?这并不在于MVP为Microsoft创造了多少价值,而在于MVP擅长通过沟通来创造价值,因此能够跟一群MVP沟通一定能为你带来价值。因此,MVP Global Summit、MVP Open Day、MVP Dinner等等每年固定的聚会我都尽量不缺席。

最后一天,除了在王洪超的Session上讲讲我熟悉的ASP.NET AJAX 4.0,我就没什么别的工作了,因此我有时间就在会场周围走走,看看有谁要盖章的。有一次我走在三层展区,看到一位美女迎面走来,她看着我想要说什么但又没说,我就猜她想要找我盖章,但又不确定我是不是宣传单张上的那个人。于是我直接走过去问她,“你是要找我盖章吗?”她说是,然后还呼唤她的同伴过来盖章。我不知道如果我不主动问她的话事情会怎么样,但机会有时候就是这个样子,如果你看到了又不主动问,你就有可能错过,而问一下又不会有什么不好的。对我来说,不为她盖章并没什么损失;对她来说,或者就要多花一些时间去找另外一位MVP了。