来源:互联网 发布:新概念英语软件安卓版 编辑:程序博客网 时间:2024/05/01 17:33

层主要有两个作用:

缓冲:在某些频繁更新的界面中,如果某些显示元素一直不变化,我们就可以将这些元素提取出来画到一个模拟的屏幕中,当界面需要更新时,只需将要刷新的元素更新到另外一个模拟屏幕,而后将两个模拟屏幕合并到真正屏幕上,这样做就省掉了不变元素的重画时间(某些元素重画很耗时,如图像显示等),从而减轻了系统负担及加速画面更新。我们把这样的模拟屏幕就叫做层,也可以说层就是屏幕的缓冲空间。

特效:应为层的格式简单且统一,并且一般的图形系统中都会用硬件来加速层合并,所以在层合并时加上些特效会很方便并且实现极快。我们系统中的特效有通透,半透明,剪切等等。

由于动画做背景有缺陷,有了层以后,我们就可以将不便的文本及图像放到新建的一个层中,将动画放到背景层中,每当有动画换帧时,只需将新的帧画到背景层中,然后合并两个层到屏幕(动画刷新时自动会合并),这样做上层的文本等就不会被动画盖住了。

创建层:

 创建层需要先建一个层句柄(可以把层句柄当作一个指向层的索引),我们都是通过层句柄来控制层的。函数gdi_layer_create用来创建层,其前四个参数指出层的位置及大小(位置是以实际屏幕左上角为原点的),最后一个参数时刚创建的层句柄地址,用以返回所创建的层。

gdi_handle my_layer;

void mmi_myapp_entry(void)

{

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(20,20,136,130, &my_layer);

    ......

}

要注意一点的是,应为创建层时系统要为其分配动态内存空间,而系统保留的内存一般只够创建一个UI_device_width * UI_device_height大小的层,所以如果调用gdi_layer_create时内存不足系统就会ASSERT.解决的办法是使用函数gdi_layer_create_using_outside_memeory,即自己申请内存,然后作为参数传进去创建层。

 

激和层:

在我们的图形系统中,任何时刻有且只能有一个层处于激和状态,所有的绘画函数都是默认画到这个层中,所以想要在层上绘画必须先将其激和。创建层并不会自动激和,需要手动将其激和:

gdi_handle my_layer;

void mmi_myapp_entry(void)

{

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(20,20,136,130, &my_layer);

    gdi_layer_set_active(my_layer);

    ......

}

 

基础层:

系统开机的时候会为每个硬件屏幕创建一个基础层,基础层有如下几个特点:

1,基础层由系统创建,无法删除。

2,与硬件屏幕完全重合(位置与大小都一样)。

3,系统默认的激和层,EntryNewScreen时系统会自动将基础层激活。

4,显示更加快速,基础层存储于芯片内的flash中,所以在其上面绘画极快,一般我们会将刷新频繁的内容放在基础层上。

由以上几个特点看出,在不使用多层的情况下,我们完全可以将基础层当成时硬件屏幕来看待,也就是说普通程序完全可以忽略层的概念。

尽管可以创建多个层,但基础层肯定时不能浪费的,这里我们将在其上绘制背景层(在激和新层之前我们的东西都默认到基础层中),在新建层上绘制文字即图标。

因系统一般只在EntryNewScreen时才会自动将基础层激活,为避免特殊情况下使用层混乱,通常在新层上绘画完毕后,我们会主动将基础层还原为激活状态:

gdi_handle my_layer;

void mmi_myapp_entry(void)

{

    ......

    gdi_handle base_layer;

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(20,20,136,130, &my_layer);

    gdi_layer_set_active(my_layer);

    ......

    gdi_layer_get_base_handle(&base_layer);

    gdi_layer_set_active(base_layer);

    gui_BLT_double_buffer(0,0,UI_device_width -1, UI_device_height -1);

}

函数gdi_layer_get_base_handle用来获取基础层的句柄。另外,用函数gdi_layer_resore_base_active()也起到相同的作用。

 

合并:

函数gui_BLT_double_buffer用来合并层,但在使用之前先得用gdi_layer_set_blt_layer指明是哪几个层需要合并,函数gui_BLT_double_buffer能接受四个层句柄,也就是说我们系统同一时刻最多能合并四个层(当然创建的层可以不止这个数)。另外要注意参数的顺序,第一个传入的层是放在最底下的,然后依次往上码。

gdi_handle my_layer;

void mmi_myapp_entry(void)

{

    ......

    gdi_handle base_layer;

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(20,20,136,130, &my_layer);

    gdi_layer_set_active(my_layer);

    ......

    gdi_layer_get_base_handle(&base_layer);

    gdi_layer_set_active(base_layer);

    gdi_layer_set_blt_layer(base_layer,my_laye,NULL,NULL);

    gui_BLT_double_buffer(0,0,UI_device_width -1, UI_device_height -1);

}

也可以直接使用gdi_layer_blt来合并层,效果一样:

gdi_handle my_layer;

void mmi_myapp_entry(void)

{

    ......

    gdi_handle base_layer;

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(20,20,136,130, &my_layer);

    gdi_layer_set_active(my_layer);

    ......

    gdi_layer_get_base_handle(&base_layer);

    gdi_layer_set_active(base_layer);

    gdi_layer_blt_(base_layer,my_laye,NULL,NULL,0,0,UI_device_width -1, UI_device_height -1);

}

 

层坐标系:

在我们的图形系统中,所有绘画函数所使用的坐标参数原点并不是硬件屏幕的左上角,而是当前激活层的左上角。

gdi_handle my_layer;

void mmi_myapp_entry(void)

{

    ......

    gdi_handle base_layer;

    S32 layer_offset_x = 20,layer_offset_y = 20;

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(layer_offset_x,layer_offset_y,136,130, &my_layer);

    gdi_layer_set_active(my_layer);

 

    gui_set_text_color(text_color);

    gui_set_font(&f);

    gui_set_text_border_color(UI_COLOR_GREEN);

    gui_measure_string((UI_string_type)GetString(STR_MYAPP_HELLO),&w,&h);

    x = (UI_device_width - w)/2 -layer_offset_x;

    y = (UI_device_height - h)/2 -layer_offset_y;

    gui_move_text_cursor(x, y);

    gui_print_bordered_text((UI_string_type)GetString(STR_MYAPP_HELLO));

    ......

    gdi_layer_get_base_handle(&base_layer);

    gdi_layer_set_active(base_layer);

    gdi_layer_blt_(base_layer,my_laye,NULL,NULL,0,0,UI_device_width -1, UI_device_height -1);

}

 

通透:

首先我们要将新层清理一下,用函数gdi_layer_clear就可以将整个层刷成单一颜色(层激活后要立即执行)。用函数gdi_layer_set_source_key将某一颜色设为层的通透色,在层合并的时候,系统会自动将层由与通透色相同的颜色忽略掉(就是说这一点上看到的是底下层的颜色)。

void mmi_myapp_entry(void)

{

    ......

    gdi_handle base_layer;

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(20,20,136,130, &my_layer);

    gdi_layer_set_active(my_layer);

    gdi_layer_clear(GDI_COLOR_BLUE);

    gdi_layer_set_source_key(TRUE,GDI_COLOR_BLUE);

    ......

    gdi_layer_get_base_handle(&base_layer);

    gdi_layer_set_active(base_layer);

    gdi_layer_blt_(base_layer,my_laye,NULL,NULL,0,0,UI_device_width -1, UI_device_height -1);

}

 

剪切:gdi_layer_set_clip

所谓剪切,就是在层中设一个限制区域,只有在这个区域中的绘画才是有效的,否则就会被自动忽略。

剪切特效有两个特点:

1,每个层一定有而且只能有一个剪切区域。

2,剪切区域一经设置,永久生效。所有剪切区域用完后最后用gdi_layer_reset_clip还原(如不还原则有可能什么东西都画不上来)

void mmi_myapp_entry(void)

{

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(20,20,136,130, &my_layer);

    gdi_layer_set_active(my_layer);

    gdi_layer_clear(GDI_COLOR_BLUE);

    gdi_layer_set_source_key(TRUE,GDI_COLOR_BLUE);

    gdi_layer_set_clip(40,25, 100, 100);

    ......

}

 

半透明:

gdi_layer_set_opacity的第一个参数指明要不要开启半透明效果,第二个参数是透明度的取值,范围从0至255,值越小表示透明度越高,当取值为0时就会完全被透掉,255即完全不透明。

void mmi_myapp_entry(void)

{

    ......

    gdi_image_draw_id(0, 0, IMG_ID);

    gdi_layer_create(20,20,136,130, &my_layer);

    gdi_layer_set_active(my_layer);

    gdi_layer_clear(GDI_COLOR_BLUE);

    gdi_layer_set_source_key(TRUE,GDI_COLOR_BLUE);

    gdi_layer_set_opacity(TRUE, 128);

    ......

}

 

释放层:

创建层需要为其分配内层空间,所以层用完后也要手动将其释放(切记一定要释放,否则别的程序就无法创建层了):

gdi_handle my_layer;

void mmi_myapp_exit(void)

{

    ......

    gdi_layer_free(my_layer);

}

void mmi_myapp_entry(void)

{

   ......

   EntryNewScreen(SCR_MYAPP_MAIN, mmi_myapp_exit, mmi_myapp_entry, NULL);

   ......

}

 

锁屏:

原理是在绘画时加入一个计数器,只在当计数器为零时gdi_layer_blt才会真正起作用

draw screen start ---------------------------------------------------------计数器 = 0

gdi_layer_lock_frame_buffer();---------------------------------------------计数器= 1

      draw title start

      gdi_layer_lock_frame_buffer();---------------------------------------计数器= 2

      ......

      gdi_layer_unlock_frame_buffer();-------------------------------------计数器= 1

      gdi_layer_blt(......);

      draw title end

      draw menu start

      gdi_layer_lock_frame_buffer();---------------------------------------计数器= 2

      ......

      gdi_layer_unlock_frame_buffer();-------------------------------------计数器= 1

      gdi_layer_blt(......);

      draw menu end

......

gdi_layer_unlock_frame_buffer();-------------------------------------计数器= 0

gdi_layer_blt(......);

draw screen end

gdi_layer_lock_frame_buffer()会将计数器加一,gdi_layer_unlock_frame_buffer()会将计数器减一,上面流程图中只有最后一次gdi_layer_blt才会起实际作用。

void mmi_myapp_entry(void)

{

   ......

   EntryNewScreen(SCR_MYAPP_MAIN, mmi_myapp_exit, mmi_myapp_entry, NULL);

   gdi_layer_lock_frame_buffer();

   ......

   ......

   gdi_layer_unlock_frame_buffer();

   gdi_layer_blt_(base_layer,my_laye,NULL,NULL,0,0,UI_device_width -1, UI_device_height -1);

}

注:gui_layer_lock_frame_buffergui_layer_unlock_frame_buffer 跟上述两个函数功能一致。

原创粉丝点击