iPhone 桌面特效设计和实现

转载请注明出处: http://www.pengliu.org/proj/iphone_desktop.html

简介

苹果公司的 iphone 手机得到业界好评,由于工作需要,我对桌面特效的实现做了深 入研究,现作简单总结。本文研究的特效包括:

  • 图标抖动,更准确的说是图标做不规律的左右摇摆;
  • 图标拖动和滑动,即图标可以从一个位置拖到另一个位置,同时受影响的图 标会按 Z 字形的规则滑动;
  • 图标缩放,点击时,图标放大;松开后图表缩小;
  • Alpha 混合,拖动一个图标和另一个图标重叠时有半透明效果

iphone 桌面的截图:

iphone desktop
iphone desktop

实现思路

基于动画原理实现抖动和缩放

动画实际是在一定的时间间隔内顺序显示一系列的相关图片实现的,由于人的视 觉有惯性,当时间间隔足够短时,就会看到物体动起来。抖动和缩放都可以基于 动画的原理实现:

  • 图标的抖动是由三桢图片做不规则切换实现的,一祯是正常的图,一桢是逆 时针转 N(N=3) 度的图,还有一桢是顺时针旋转 N(N=3) 度的图;
  • 图标的缩放是由一大、一小两桢图片组成,为了增加柔和性,中间可以增加 一桢或两桢;
  • 在实际实现时,所有的图片的画布都取相同尺寸,这样便于贴图和绘制

图标的拖动

拖动的实现比较简单,只需随鼠标不断改变图标的位置并实时显示即可。有一点 要注意,当在新的位置绘制图片时,要把原来的擦掉,否则就会出现“贪吃蛇”现象,造 成混乱。

Alpha 混合

半透明采用 Alpha 混合来实现,即将拖动的图标绘制在一个带 Alpha 混合的层 上,然后将这个层 bilbit 到绘制层即可。

为了屏蔽背景色,可能还会用到 color key。

桢数据的管理

根据上述分析,为了实现一个图标的抖动和缩放,我准备 3 桢图由于抖动,2 桢图用于缩放,当图标很多时,图片数据就会很多,管理是个问题。为了便于管 理,并且考虑到绘制速度问题,我采用了矩阵的方式来组织。

假设有 N 个图标,每个图标有 M 桢图。在程序启动时,把所有图片读到一块 mem dc 中排列成一个 N 行 M 列的矩阵。一个图标的 M 桢图放在同一行中,有 多少个图标就有多少个行。

下图是一个 5 桢 3 个图标的数据布局图:

frame1 frame2 frame3 frame4 frame5
icon1 icon1_lft icon1_rgt icon1_zi_bigger icon1_zi_biggest
icon2 icon2_lft icon2_rgt icon2_zi_bigger icon2_zi_biggest
icon3 icon3_lft icon3_rgt icon3_zi_bigger icon3_zi_biggest

绘制方法

考虑到绘制速度和 Alpha 混合的需要,我设置了 4 个 dc:

  • texture_dc:保存图标数据的 dc
  • blending_dc:带 Alpha 混合的层
  • drawing_dc:用于绘制的dc,所有绘制先在这里完成,然后 bilbit 到屏幕 上
  • screen_dc:屏幕 dc,代表屏幕

绘制的伪代码如下:


    for (i = 0; i < NR_PANEL; i++) {
        if (blending)
            bilbit (texture_dc, frame_id , icon_id, W, H ,
                        blending_dc, 0, 0, 0);
        else
            bilbit (texture_dc, frame_id, icon_id, W, H,
                        drawing_dc, 0, 0, 0);
    }
    bilbit (blending_dc, 0, 0, W, H, drawing_dc, 0, 0, 0);
    bilbit (drawing_dc ,0, 0, W, H, screen_dc, 0, 0, 0);


针对每个 panel,首先从 texture_dc 取祯数据,bilbit 到 drawing_dc 上;若是拖动的桢 bilbit 到 blending_dc 上;当所有 panel 绘 制完毕后,将 blending_dc bilbit 到 drawing_dc 上;所有的 panel 和绘制 完后,将 blending_dc 的数据 bilbit 到 drawing_dc ,最后把 drawing_dc 的数据 bilbit 到 screen_dc,显示出来。

同步

动画的计时和实时重绘由一个定时器 (timer) 来控制,没过一定的时间间隔, 就会产生一个 TIMER 消息,此时屏幕所有的图标的要重新绘制一次,绘制完毕 后要修改当前桢,为一次绘制作准备。

数据结构

IPPANEL

IPPANEL 指的是一个 panel 容器,它是图标的容器,每个图标都显示在一个 panel 中。该结构定义了一个区域和图标 id 。


typedef struct _IPPANEL {
    RECT rect;
    int icon_id;
} IPPANEL;

IPANIMATION

IPANIMATION 定义了一个动画,它定义了动画的起点、终点,起始祯和终止祯


typedef struct _IPANIMATION {
    POINT start_point;
    POINT end_point;
    int start_frame_id;
    int end_frame_id;
} IPANIMATION;

IPICON

IPICON 定义了一个图标,给出了图标的当前显示位置,当前要显示的桢,动作 类型和动画信息。

在这里定义并处理了三种动画类型,一是抖动,二是放大,三是滑动。


typedef struct _IPICON {
    int x;
    int y;

    int type;
    int cur_frame;
    IPANIMATION animation;

    int panel_id;
} IPICON;


核心控制流程

IPICON 是核心数据结构,一个 IPICON 代表一个 ICON 对象;Timer 是同步全 局的控制中心,它每隔一个 interval 会重绘所有图标。

case TIMER:

    /* 擦除屏幕 */
    SetBrushColor (drawing_dc, COLOR_black);
    FillBox (drawing_dc, 0, 0, SCREEN_W, SCREEN_H);

    for (i = 0; i < NR_PANEL; i++) {
        switch (incon.type) {
            case AM_NORMAL:
                ... swapping...
                break;

            case AM_ZOOMIN:
                ... Zoom in ...
                break;

            case AM_SLIDE:
                ... slide ...
            break;
        }
    }

    bilbit (blending_dc, 0, 0, W, H, screen_dc, 0, 0, 0);
    bilbit (drawing_dc, 0, 0, W, H, screen_dc, 0, 0, 0);

其它

foot bar