列表界面Iphone式平滑效果实现

一:MTK原列表菜单的实现方式

列表界面,有一个结构体变量记录列表菜单的各种信息MMI_fixed_list_menu,对其中几个成员说明

MMI_fixed_list_menu.x,MMI_fixed_list_menu.y为列表菜单显示区域的起始坐标,

MMI_fixed_list_menu.width,MMI_fixed_list_menu.height为列表菜单显示区域的宽和高,

MMI_fixed_list_menu.n_items为列表菜单的item个数,

MMI_fixed_list_menu.first_displayed_item为显示区域的第一个显示的item index值,

first_displayed_item的值为0到n_items-1,

MMI_fixed_list_menu.last_displayed_item为显示区域的最后一个显示的item index值,

MMI_fixed_list_menu.highlighted_item为当前高亮的itemindex值,

原来MTK列表界面绘制原理是这样的,从列表的MMI_fixed_list_menu. first_displayed_item开始,一条一条菜单绘制,用一个初始化为0的变量total_height记录绘制的菜单高度,每绘制一个item,total_height的值就增加一个item的高度,每次绘制item之前,会对total_height和MMI_fixed_list_menu.height进行比较,发现total_height>=MMI_fixed_list_menu.height就中断绘制,其流程如下:

fixed_list_menu *m= &MMI_fixed_list_menu;//用一个指针m指向MMI_fixed_list_menu

counter = 0//计数器

for (i =m->first_displayed_item; (i < m->n_items && !done); i++)

{

       total_height += iheight;

       if (total_height < list_height + 1)

{

       item_display_function(i);//绘制第i个item

       counter++;

}

}

m->last_displayed_item= m->first_displayed_item + counter – 1//计算最后一个菜单item值

这种显示方式,会带来一个问题,在滑动菜单上特别明显,严重影响了酷炫体验,一是滑动列表菜单时,不能将菜单停留在任意位置,first_displayed_item的起始位置,始终在标题栏的下方开始的位置,不能出现第一个item显示一部分,最后一个item显示一部分这种情况,当用手拖动列第一个item没有和标题栏下方对齐时,菜单就会强制对齐,这样列表界面就有明显的跳跃现象,滑动的坐标就不是连续的。

 

二:

1:为了解决上述问题,对MTK的列表菜单显示机制做了修改,在MMI_fixed_list_menu结构体里面,添加一个成员变量MMI_fixed_list_menu.menu_offset_y,用来记录第一个菜单相对列表界面起始位置MMI_fixed_list_menu.y的偏移量,我们知道,进入一个新菜单后,原来的菜单信息需要保存历史,这样回来的时候,保证显示的位置和原来的一直,所以MMI_fixed_list_menu.menu_offset_y需要像MMI_fixed_list_menu. first_displayed_item一样,保存到历史中去。

通过上图详细讲解新的列表显示机制。

假如进入一个列表界面,该列总item数为10,当初次进入该列表时,item从item1显示到item6,每个item的高度为item_height,当触摸笔从down_y滑动到up_y时

m->menu_offset_y= down_y - up_y;

根据menu_offset_y计算第first_displayed_item和last_displayed_item

m->first_displayed_item= m->menu_offset_y/item_height;

m->last_displayed_item = (m->menu_offset_y + m->height - 1) /item_height;

根据menu_offset_y计算first_displayed_item和m->y的偏移值item_offset_y;

item_offset_y =m->menu_offset_y%item_height;

这时候列表显示应该是从item1到item8,这样就有两个item需要特殊处理,item1和item8,因为列表和状态栏,标题栏,按键栏属于同一个layer,都是base layer,直接绘制item1和item8的绿色部分就会将标题栏和按键栏覆盖掉。当列表绘制,判断为fist item和last item时,不用原来item_display_function函数处理,通过自己添加的一个函数item_copy_handle处理,在item_copy_handle函数中,新建一个new layer,在new layer上绘制第一个item和最后一个item,然后把上图中红色部分flatten到base layer上。这样就显示出了item1到item8,并且实现了item的部分显示,这样就可以做到菜单连续坐标的平滑效果,红色flatten区域的计算

显示第一个item的flatten区域计算:

flatten_x1 =m->x,;

flatten_y1 =m->y;

flatten_x2 =m->x + m->width – 1;

flatten_y2 =m->y + (item_height - menu_offset_y);

显示最后一个item的flatten区域计算

flatten_x1 =m->x,;

flatten_y1 =(m->y +m->height-1) - menu_offset_y;

flatten_x2 =m->x + m->width – 1;

flatten_y2 = m->y+m->height-1;

 

 

新的列表菜单绘制流程伪代码如下:

for (i =m->first_displayed_item;  i <=m->last_displayed_item;  i++)

{

  if(i==m->first_displayed_item  ||  i==m->last_displayed_item)

{

       item_copy_handle(i);//特殊处理first item和last item

}

else

{

              item_display_function(i);//绘制第i个item

}

}

 

2:关于自由滑动的实现,自由滑动就是触摸笔在列表上快速滑动一段距离后,离开触摸屏时,菜单会继续朝触摸笔滑动的方向自由滑动一段距离。

实现方式如下:在滑动过程中,用一个数组不断记录最近50个move事件的时间和位置,当触摸笔离开触摸屏时,对这50个move事件信息进行处理,通过相邻两个move事件的时间delta_time和距离delta_y,计算出最快的move事件,即delta_y/delta_time的值最大,

将delta_y/delta_time再乘一个系数RUN_REFRESH_SCREEN_INTERVAL作为自由运动量free_run_momentum,滑动方向为从屏幕下方往上方滑动时,free_run_momentum为正,往屏幕下方滑动时,free_run_momentum为负。然后启动一个定时器不断刷新列表显示,通过不做设置m->menu_offset_y = m->menu_offset_y+free_run_momentum实现整个列表往前或往后自由滚动 ,每次刷新,将free_run_momentum乘一个衰减系数REDUCE_COEFFICIENT实现不断的衰减,实现列表界面的滑动由快变慢效果,一直衰减到free_run_momentum为0为止。通过调整系数RUN_REFRESH_SCREEN_INTERVAL和衰减系数就可以调节滑动的快慢效果。

 

3:关于过冲实现:最大过冲距离为m->height的1/3,这个值可以随意调整

过冲效果示意图如下:

过冲1,第一个item下拉到最大距离low_bound, low_bound = -(m->height/3);

过冲2,最后一个item上拉到最大距离hight_bound,

hight_bound =(m->n_items * item_height) - m->heigh + (m->height/3);

过冲1时菜单往回滑动过程:

往下拖动菜单到最大位置,这时候m->menu_offset_y值为low_bound,触摸笔离开触摸屏时,设置菜单最终应回的位置的g_gui_ssp_free_run_final_pos值和自由滚动量

free_run_momentum值,

free_run_momentum= low_bound;

g_gui_ssp_free_run_final_pos= 0;

然后启动定时器,通过不断计算m->menu_offset_y值和刷屏实现菜单往回滑动,

m->menu_offset_y的计算方法如下:

m->menu_offset_y=g_gui_ssp_free_run_final_pos+free_run_momentum*REDUCE_COEFFICIENT

最终菜单往回滑动到第一个item与标题栏对齐

过冲2时菜单往回滑动过程:

往上拖动菜单到最大位置,这是这时候m->menu_offset_y值为height_bound,触摸笔离开触摸屏时,设置菜单最终应回的位置的g_gui_ssp_free_run_final_pos值和自由滚动量

free_run_momentum值,

free_run_momentum= m->height/3;

g_gui_ssp_free_run_final_pos= (m->n_items * item_height) - m->heigh;

然后启动定时器,通过不断计算m->menu_offset_y值和刷屏实现菜单往回滑动

m->menu_offset_y的计算方法如下:

m->menu_offset_y=g_gui_ssp_free_run_final_pos+free_run_momentum*REDUCE_COEFFICIENT

最终菜单往回滑动到最后一个item与按键栏对齐

示意图如下:

 

 

4:列表菜单无高亮的实现:在之前触摸项目中,列表菜单的高亮条是一直存在的,每次滑动落笔时,就会高了到落笔那个item,自由滑动过程中,当高亮item滑出列表菜单显示范围2,滑动停止后,又会高亮到显示第一个或者最后一个item上,这种也会给人一种闪烁感,于是去掉列表滑动时的item高亮,只有在按住菜单item不放或者只单击item时才出现高亮。

刷新列表时,是否绘制高亮,用一个全局变态控制。

按住菜单item高亮的实现方式:落笔时,启动一个200ms定时器,在200ms时间到,定时器回调函数中判断,当前pen状态还在点击非move状态,重新刷新列表,并绘制高亮。

单击高亮的实现方式:单击提笔时,在相应单击操作之前重新刷新列表,并绘制高亮,在相应单击操作。

这种无高亮会带来一个问题,操作按键栏选项时,不知道当前操作的是哪个item,于是就将原来的选项操作分成两部分,一部分仍放在选项操作里面,即对所有item都有效的操作,比如删除全部,标记多个等,一部分通过长按item操作里面,即对单个item的操作,比如删除,重命名等。按照这种方式,如果每个模块都去更改菜单树,那代价太大,更改的地方太多,于是这种操作统一在滑动模块中处理,不管是点击选项还是长按item,都相应原来的选项操作,但是添加一个变量,记录当前操作是点击选项还是长按item,各应用模块只需要在原来的选项操作函数里面,通过获得该变量的值去对菜单的item进行hide或者unhide操作,就可以实现长按item和点击选项,进入不同的菜单,进行不同的操作,而不需要添加或更改原来的函数接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值