multlist控件

一、使用场景

在应用程序开发过程中,对于多个元素按行或按列顺序排列情况,很多具有相同的功能。比如:

  1. 进度条实时显示滑动的进度

  2. 多行排列需按弧形的路径实现变形缩放功能

  3. 滑动结束后具备对齐动画

  4. 滑动到头尾时具备回弹动画

  5. 滑动滑动过程中需实现动态添加和删除

本控件主要对上述功能进行封装,并提供一系列接口用于统一管理item的位置、对齐、回弹,缩放、滑动删除等。所有item通过list链表管理,并提供item增、删、改、查等功能。

二、功能介绍

1、功能配置

为了简化接口数量,将有关接口以标志位的形式提供。即只需使能或重置相应的标志位即可使能或清除相关功能。

enum
{
    LV_MULTLIST_FLAG_THROW                  = (1U << 0),  // 是否使能惯性滑动,默认使能
    LV_MULTLIST_FLAG_LOOP                   = (1U << 1),  // 是否使能循环模式,默认不使能
    LV_MULTLIST_FLAG_RESIDENCY              = (1U << 2),  // 剧中对齐时,是否是元素的间隔对准屏幕中心,默认不使能
    LV_MULTLIST_FLAG_BEZIER_ALG             = (1U << 3),  // 是否使能了贝塞尔变形,设置贝塞尔参数后只能使能
    LV_MULTLIST_FLAG_ELLIPSE_ALG            = (1U << 4),  // 是否使能椭圆形的偏移
    LV_MULTLIST_FLAG_EDGE                   = (1U << 5),  // 是否使能edge事件,用于与lvsf_multedge控件交互
    LV_MULTLIST_FLAG_SCROLLBAR              = (1U << 6),  // 是否使能进度条,用于与lvsf_scrilbar控件交互
    LV_MULTLIST_FLAG_BOUNDARY               = (1U << 7),  // 控件创建后时候不删除,只是隐藏,常驻与list节点内
    LV_MULTLIST_FLAG_LOCK_SCRL              = (1U << 8),  // 锁定scrl的滑动,
    LV_MULTLIST_FLAG_SNAPSHOT               = (1U << 9),  // 使能item的元素拍照功能
    LV_MULTLIST_FLAG_TOW_PAGE               = (1U << 10), // 使能两页的刷新模式
    LV_MULTLIST_FLAG_THREE_PAGE             = (1U << 11)  // 使能三页页的刷新模式
};
typedef uint32_t lv_multlist_flag_t;

//功能配置接口
int lv_multlist_has_flag(lv_obj_t *multlist, uint32_t flag);  	//查询是否开启了相关功能
void lv_multlist_add_flag(lv_obj_t *multlist, uint32_t flag);	//添加相应功能位标识
void lv_multlist_clear_flag(lv_obj_t *multlist, uint32_t flag);	//清楚相应功能位标识

2、事件说明

为了简化接口控件之间的交互逻辑,将有关回调函数以事件的形式提供,如进度条的刷新事件,对齐事件、滑动事件等。

//mutlist在特定状态会发送相应事件,通知应用程序处理事件逻辑,每种事件意义和用途可查阅具体应用案例
enum
{
    LV_EVENT_EDGE_DRAGE_REQ = _LV_EVENT_LAST + 1, //edge控件拖动请求事件
    LV_EVENT_EDGE_DRAGE_RES,	//edge控件拖动确认事件
    LV_EVENT_EDGE_DRAGE_BEGIN,	//edge控件拖动开始事件
    LV_EVENT_EDGE_DRAGING,		//edge控件拖动中事件
    LV_EVENT_EDGE_DRAGE_END,	//edge控件拖动结束事件
    LV_EVENT_EDGE_CHANGE_DIR, 	//开始滑动事件
    LV_EVENT_LIST_SCROLL_STRAT,  //开始滑动事件
    LV_EVENT_LIST_SCROLLING,	//滑动中事件
    LV_EVENT_LIST_SCROLL_END,	//滑动结束事件
    LV_EVENT_LIST_FOCUS,		//item对齐时发送该事件
    LV_EVENT_LIST_FOCUS_LOSS,	//item离开对齐位置时发送
    LV_EVENT_LIST_SCROLLBAR,	//更新进度条进度事件
    LV_EVENT_SWIPE_DELETE,		//有元素节点滑动删除时发送该事件
    LV_EVENT_LIST_LAST			//无效事件
};
//应用程序可用事件主要有滑动事件、焦点事件,滑动删除事件

以平铺的事件回调为例说明multlist事件使用方法:

void tlv_event_cb(lv_event_t *e)
{
    lv_obj_t *multlist = lv_event_get_current_target(e);
    lv_event_code_t code = lv_event_get_code(e);

    if (LV_EVENT_LIST_FOCUS == code)
    {
        //在平铺页面中,在对齐事件时激活当前tlv应用
        g_tlv->state = TLV_STATE_RESUME;
        tlv_resume_cur(g_tlv);
    }
    else if (LV_EVENT_LIST_FOCUS_LOSS == code)
    {
        //在平铺页面中,在丢失对齐事件时暂停当前tlv应用
        g_tlv->state = TLV_STATE_PAUSE;
        tlv_pause_cur(g_tlv);
    }
    else if (LV_EVENT_EDGE_DRAGE_RES == code)
    {
        lv_multlist_edge_t *edge_para = lv_event_get_param(e);
        {
            //接受到滑动开始事件时,pause当前tlv,将控制权让给edge悬浮窗口
            lv_multlist_disable_encoder(multlist);
            tlv_pause_cur(g_tlv);
            lv_multlist_add_flag(g_tlv->multlist, LV_MULTLIST_FLAG_LOCK_SCRL);
            lv_multlist_disable_encoder(g_tlv->multlist);
        }
    }
    else if (LV_EVENT_EDGE_DRAGE_END == code)
    {
        //接受到滑动结束事件时,resume当前tlv,将控制权激活
        lv_multlist_edge_t *edge_para = lv_event_get_param(e);
        if (0 == edge_para->process)
        {
            if (LV_EDGE_LEFT == edge_para->trige_type)
                tlv_anim_config(&nvm_sys_get(tlv_anim));
            tlv_resume_cur(g_tlv);
            lv_multlist_enable_encoder(g_tlv->multlist, 10, 100, true);
            lv_multlist_clear_flag(g_tlv->multlist, LV_MULTLIST_FLAG_LOCK_SCRL);
        }
    }
    else if (... == code)
    {

    }
}

3、对齐方式

对齐指滑动结束后item的对齐位置,主要有:无对齐、头对齐、剧中对齐、尾对齐。

  1. ​ 无对齐表示滑动结束后没有对齐动作;

  2. ​ 头对齐表示滑动结束后item元素对齐到屏幕的顶部;

  3. ​ 尾对齐表示滑动结束后item元素对齐到屏幕的低部;

  4. ​ 剧中对齐表示滑动结束后item元素对齐到屏幕中心;

//1、对齐类型
enum
{
    LV_MULTLIST_ALIGN_NONE,		//取消对齐
    LV_MULTLIST_ALIGN_CENTER,	//中心对齐
    LV_MULTLIST_ALIGN_HEAD,		//头对齐
    LV_MULTLIST_ALIGN_TAIL,		//尾对齐
} ;
typedef  uint8_t lv_multlist_align_t;
//通过设置对齐接口,指定multlist的对齐方式
void lv_multlist_set_align(lv_obj_t *multlist, lv_multlist_align_t align, lv_coord_t offset);

//2、主动对齐接口,主要用于初始化的时候指定对齐的位置
//主动调用头对齐,将指定的item对齐到头部
void lv_multlist_align_head_to(lv_obj_t *multlist, uint16_t index, lv_coord_t edge_offset);
//主动调用居中对齐,将指定的item居中对齐
void lv_multlist_align_tail_to(lv_obj_t *multlist, uint16_t index, lv_coord_t edge_offset);
//主动调用尾对齐,将指定的item对齐尾部
void lv_multlist_align_center_to(lv_obj_t *multlist, uint16_t index, lv_coord_t edge_offset);

4、缩放变形

multlist可以使能贝塞尔算法的缩放以及椭圆弧度的偏移,例如,单独使能贝塞尔变形以及两种算法都使能的情况如图所示

float para[] = { 0, 0, 0, 0.1f, 0.3f };
lv_multlist_set_bezier_para(multlist, LV_VER_RES_MAX*3.0f/2, para, para);
lv_multlist_set_ellipse_para(multlist, LV_VER_RES_MAX, LV_VER_RES_MAX+100);
fishy

贝塞尔变形

void lv_multlist_set_bezier_para(lv_obj_t *multlist, uint32_t range, float *pos_arr, float *neg_arr)

接口说明:用于设置item缩放的贝塞尔算法参数

  • multlist:multlist实例

  • range:贝塞尔算法的范围,超过此范围的item无效

  • pos_arr:正向偏移的缩放系数,大小为逐级递增,范围[0,1],数组长度为5

  • neg_arr:负向偏移的缩放系数,大小为逐级递增,范围[0,1],数组长度为5

弧形偏移

void lv_multlist_set_ellipse_para(lv_obj_t *multlist, lv_coord_t x_axis, lv_coord_t y_axis)

接口说明:用于设置item的弧形偏移

  • multlist:multlist实例

  • x_axis:椭圆弧度X轴方向的轴长

  • y_axis:椭圆弧度Y轴方向的轴长

5、回弹配置

回弹主要配置回弹区域大小,设置item超出头部或尾部拉出的最大位置,滑动结束后的回弹位置也需配置。

fishy
void lv_multlist_set_scrl_pad(lv_obj_t *multlist, lv_coord_t head, lv_coord_t tail)

接口说明:用于配置回弹最大区域

  • multlist:multlist实例

  • head:头部最大偏移距离,一般为multlist滑动方向一半

  • tail:尾部最大偏移距离,一般为multlist滑动方向一半

fishy
void lv_multlist_set_springback(lv_obj_t *multlist, lv_coord_t edge_head, int16_t edge_tail);

接口说明:用于设置回弹结束后的位置

  • multlist:multlist实例

  • edge_head:头部对齐后偏移multlist的头部间隔

  • edge_tail:尾部最对齐后偏移multlist的底部间隔

6、节点管理

multlist的节点值item链表中的元素,对于这些节点提供了增、删,改、查的功能,且对于节点的删除,可使用内置的删除动画。

节点信息添加

lv_multlist_item_t *lv_multlist_add_info(lv_obj_t *multlist, lv_coord_t w, lv_coord_t h, void *info, void *user_data);

接口说明:向item链表中添加节点信息,用于multlist节点管理

  • multlist:multlist实例

  • w:头部对齐后偏移multlist的头部间隔

  • h:尾部最对齐后偏移multlist的底部间隔

  • info:节点信息,标识item的信息

  • user_data:用户自定义数据

节点查询

lv_multlist_item_t *lv_multlist_get_item_by_index(lv_obj_t *multlist, int16_t index);

接口说明:通过索引值获取对应的item

  • multlist:multlist实例

  • index:索引值,唯一标识item

节点删除

uint8_t lv_multlist_item_remove(lv_obj_t *multlist, lv_multlist_item_t *delete_item, uint8_t en_anim, uint8_t free);

接口说明:删除指定的item,并指示是否开启删除动画

  • multlist:multlist实例

  • delete_item:需要产出的item

  • en_anim:是否启动删除动画

  • free:动画结束后是否释放内存

void lv_multlist_remove_info_all(lv_obj_t *multlist);

接口说明:清除所有的节点信息,一般用于pause后删除重新添加节点

  • multlist:multlist实例

节点交换

uint8_t lv_multlist_item_move_before(lv_obj_t *multlist, lv_multlist_item_t *insert_item, lv_multlist_item_t *item_ref, uint8_t en_anim);

接口说明:对于原始交换时,改变item在链表中的位置,即显示的排列顺序

  • multlist:multlist实例

  • insert_item:先通过lv_multlist_item_remove删除该节点信息,不要释放内存,即先将item从链表移除

  • item_ref:插入位置的后一个节点item,用于位置的标识

7、堆叠窗口

堆叠菜单以封装在multlist的实现中,在传统的初始化流程中需添加堆叠元素的个数,从而快速实现堆叠菜单

void lv_multlist_set_overlap_cnt(lv_obj_t *multlist, uint16_t overlap_cnt);

8、编码器接口

用于滚轮滑动时,控制item移动。

//1、使能滚轮
void lv_multlist_enable_encoder(lv_obj_t *multlist, uint32_t ratio, uint32_t vect_max, uint8_t reverse);
//2、移除滚轮
void lv_multlist_disable_encoder(lv_obj_t *multlist);

9、进出动画

enum
{
    LV_MULTLIST_FLY_LEFT_TOP,
    LV_MULTLIST_FLY_RIGHT_TOP,
    LV_MULTLIST_FLY_LEFT_MID,
    LV_MULTLIST_FLY_RIGHT_MID,
    LV_MULTLIST_FLY_LEFT_BOTTOM,
    LV_MULTLIST_FLY_RIGHT_BOTTOM,
};
typedef  uint8_t lv_multlist_fly_type_t;

void lv_multlist_fly_anim(lv_obj_t *multlist, lv_multlist_fly_type_t type, uint16_t delay, uint32_t time, uint8_t fly_in, lv_anim_ready_cb_t ready_cb);

接口说明:用于multlist中item的进出动画(可参考动画设置页面)

  • multlist:multlist实例

  • type:动画类型,分为上中下,以及左右

  • time:插入位置的后一个节点item,用于位置的标识

  • fly_in:指示时飞入动画,还是飞出动画

  • ready_cb:动画借宿回调函数

三、案例详解

1、控件使用说明

控件根据使用场景的不用分为两种:节点信息改变和节点信息不变

方式1、节点信息不变的情况下,

1、初始化流程

  • 创建控件

  • 配置控件外观属性

  • 配置LIST特殊属性

  • 注册元素回调函数

  • 添加info节点信息

  • 设置初始对齐位置

  • 添加插件属性

2、激活流程

  • 控件激活

  • 使能编码器

3、暂停流程

  • 控件暂停

  • 重置编码器

4、销毁流程

  1. 删除控件

方式2、节点信息改变的情况

1、初始化流程

  • 创建控件

  • 配置控件外观属性

  • 配置LIST特殊属性

  • 注册元素回调函数

  • 添加插件属性

2、激活流程

  • 添加info节点信息

  • 设置初始对齐位置

  • 控件激活

  • 选择性是能编码器

3、暂停流程

  • 控件暂停

  • 删除info节点信息

  • 选择性暂停编码器

4、销毁流程

  • 删除控件

2、典型应用

主要参看app_mainmemu_list.c主菜单的实现。

1、初始化流程

//1.创建控件
lv_obj_t *multlist = lv_multlist_create(lv_scr_act());

//2.配置控件外观属性
lv_obj_remove_style_all(multlist);
lv_obj_set_size(multlist, LV_HOR_RES_MAX, LV_VER_RES_MAX);
lv_obj_set_style_bg_color(multlist, LV_COLOR_BLACK, 0);
lv_obj_set_style_bg_opa(multlist, 255, 0);
lv_obj_center(multlist);
lv_obj_refr_size(multlist);

//3.配置LIST特殊属性
float para[] = { 0, 0, 0, 0.1f, 0.3f };
lv_multlist_set_bezier_para(multlist, LV_VER_RES_MAX, para, para);
lv_multlist_add_flag(multlist, LV_MULTLIST_FLAG_BOUNDARY);
lv_multlist_set_gap(multlist, ICON_VER_GAP);
lv_multlist_set_scrl_pad(multlist, LV_VER_RES_MAX >> 1, LV_VER_RES_MAX >> 1);
lv_multlist_set_dir(multlist, LV_MULTLIST_DIR_VER);//LV_MULTLIST_DIR_HOR

//4.注册元素回调函数
lv_multlist_set_item_cb(multlist, mainmenu_list_new_item_cb, NULL, NULL);

//5.添加节点info信息
lv_multlist_add_info(menu, LV_HOR_RES_MAX, BG_BTN_HEIGHT, (void *)app, NULL);

//6.设置初始对齐位置
lv_multlist_set_springback(multlist, ICON_VER_GAP, ICON_VER_GAP);
lv_multlist_align_center_to(multlist, 2, 0);

//7.添加进度条
lv_scrollbar_create(multlist, LV_SCROLLBAR_SQUARE_TYPE);

2、激活流程

//1.控件激活
lv_multlist_on_resume(multlist);
//2.使能编码器
lv_multlist_enable_encoder(multlist, 100, 1000, false);

3、暂停流程

//1.暂停控件
lv_multlist_on_pause(multlist);
//2.停用编码器
lv_multlist_disable_encoder(multlist);

4、销毁流程

//1.框架自动销毁当前页面的控件
lv_obj_del(multlist)

3、堆叠实现

1、初始化流程

//1.创建list控件
    lv_obj_t *multlist = lv_multlist_create(parent);
    
//2.设置控件外观属性
lv_obj_remove_style_all(multlist);
lv_obj_add_flag(multlist, LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_set_size(multlist, LV_HOR_RES_MAX, LV_VER_RES_MAX);
lv_obj_center(multlist);
lv_obj_refr_size(multlist);

//3.设置list的类型参数属性
float para_pos[] = { 0, 0.01f, 0.2f, 0.5f, 0.8f }; 	 //只需下半屏item有缩放效果
float para_neg[] = { 0, 0, 0, 0, 0 };				//上半屏不需缩放
lv_multlist_set_bezier_para(multlist, 80, para_pos, para_neg);
lv_multlist_set_gap(multlist, OVERLAP_GAP);
lv_multlist_set_dir(multlist, LV_MULTLIST_DIR_VER);
lv_multlist_set_scrl_pad(multlist, 0, LV_VER_RES_MAX >> 1);
lv_multlist_set_overlap_cnt(multlist, 3);			//堆叠菜单主要属性设置堆叠的个数
lv_multlist_set_align(multlist, LV_MULTLIST_ALIGN_TAIL, -OVERLAP_REF_POS); //设置堆叠位置

//4.设置动态item的回调函数,以及添加item的info信息到链表
lv_multlist_set_item_cb(multlist, overlap_item_create, overlap_item_delete, NULL);

//5.对齐位置与之前配置的参数有关,需最后配置
lv_multlist_set_springback(multlist, OVERLAP_GAP, OVERLAP_REF_POS);

2、激活流程

//1.滞后info节点
overlap_list_add_info(p_overlap->bg_list);
//2.使能控件
lv_multlist_on_resume(p_overlap->bg_list);
//3.设置对其item
lv_multlist_align_tail_to(p_overlap->bg_list, 1, 0);
//4.使能编码器
lv_multlist_enable_encoder(p_overlap->bg_list, 20, 300, true);

3、暂停流程

//1.删除items
lv_multlist_on_pause(p_overlap->bg_list);
//2.删除info节点信息,与激活流程相对应
lv_multlist_remove_info_all(p_overlap->bg_list);
//3.删除编码器
lv_multlist_disable_encoder(p_overlap->bg_list);

4、销毁流程

//1.框架自动删除

4、平铺实现

1)初始化流程

 //1.创建list控件
    lv_obj_t *multlist = lv_multlist_create(parent);
//2.设置控件外观属性
lv_obj_remove_style_all(multlist);
lv_obj_set_size(multlist, hor_res, ver_res);
lv_obj_set_style_bg_color(multlist, lv_color_hsv_to_rgb(0, 0, 0), 0);
lv_obj_set_style_bg_opa(multlist, 255, 0);
lv_obj_center(multlist);
lv_obj_refr_size(multlist);

//3.设置list的类型参数属性
lv_multlist_set_align(multlist, LV_MULTLIST_ALIGN_CENTER, 0);
lv_multlist_clear_flag(multlist, LV_MULTLIST_FLAG_THROW);
lv_multlist_set_gap(multlist, 0);
lv_multlist_set_dir(multlist, LV_MULTLIST_DIR_HOR);
lv_multlist_set_anim_para(multlist, 2, 20, 300);
lv_multlist_set_refresh_cb(multlist, tileview_refresh_cb);//配置自定义刷新函数

//4.设置动态item的回调函数,以及添加item的info信息到链表
lv_multlist_set_item_cb(multlist, tileview_create_item, tileview_delete_item, NULL);
lv_obj_add_event_cb(multlist, tileview_event_cb, LV_EVENT_ALL, tlv);

//5.对齐位置与之前配置的参数有关,需最后配置
lv_multlist_set_scrl_pad(multlist, LV_HOR_RES_MAX >> 1, LV_HOR_RES_MAX >> 1);
lv_multlist_set_springback(multlist, 0, 0);

2)激活流程

//1.添加节点信息
tileview_add_info(g_tlv->multlist);
//2.使能控件
lv_multlist_on_resume(g_tlv->multlist);
//3.使能编码器
lv_multlist_enable_encoder(g_tlv->multlist, 10, 300, true);
//4.配置对其位置
if (g_tlv->cur_item)
    lv_multlist_align_center_to(g_tlv->multlist, g_tlv->cur_item->index, 0);
else
    lv_multlist_align_center_to(g_tlv->multlist, 0, 0);
lv_multlist_focus_near(g_tlv->multlist, 0, false, false);

3)滑动过程

滑动过程中主要考虑是否注册了滑动动画接口回调函数。在动画回调函数中,根据item元素的位置实现所有动画播放。

  • 1、滑动结束时,隐藏拍照

  • 2、滑动开始,拍照当前tlv

  • 3、获取当前的动画类型

  • 4、创建multanim实例,

  • 5、设置当前动画类型,并初始化相关参数

  • 5、配置主、次动画图片

  • 6、设置当前的动画进度

static void tlv_switch_anim(lv_obj_t *multlist, lv_multlist_item_t *item, int32_t offset)
{
    int32_t offset_abs = LV_ABS(offset);
    if (TLV_STATE_PAUSE == p_tlv->state)
    {
        /*Delete snapshot in pause state, when it exceeds the center position of the screen*/
        if (offset_abs > LV_HOR_RES_MAX && item->snapshot)
        {
            lv_obj_del(item->snapshot);
            item->snapshot = NULL;
        }
        /*Create a snapshot in pause state and display it within the screen range*/
        if (offset_abs < LV_HOR_RES_MAX && NULL == item->snapshot)
        {
            lv_img_dsc_t *dsc = p_tlv->img_dsc;
            lv_multlist_item_t *cent = lv_multlist_get_center_item(multlist);
            if (cent && cent->snapshot)
                dsc = (dsc == lv_img_get_src(cent->snapshot)) ? (dsc + 1) : dsc;
            tlv_item_take_snapshot(item, dsc);
        }
        if (item->snapshot)
            lv_obj_clear_flag(item->snapshot, LV_OBJ_FLAG_HIDDEN);
    }
    /*Hide snapshot for all resume statuses*/
    if (TLV_STATE_RESUME == p_tlv->state && item->snapshot)
    {
        lv_obj_del(item->snapshot);
        item->snapshot = NULL;
        lv_obj_clear_flag(item->element, LV_OBJ_FLAG_HIDDEN);
    }

    if (item->snapshot)
    {
        /*Select the corresponding multanim animation for the type with more TLV configuration animation*/
        uint8_t anim_type = TLV_ANIM_TYPE_FIRST;
        uint32_t target_anim = LV_MULTANIM_ZOOM;
        switch (p_tlv->anim_cfg.trans)
        {
        case TLV_ANIM_TRANS_ZOOM:
            target_anim = LV_MULTANIM_ZOOM;
            break;
        case TLV_ANIM_TRANS_FADE:
            target_anim = LV_MULTANIM_FADE;
            anim_type = TLV_ANIM_TYPE_SECOND;
            break;
        case TLV_ANIM_TRANS_TURN_3D_HOR:
            target_anim = LV_MULTANIM_3D;
            break;
        case TLV_ANIM_TRANS_TURN_Y:
            target_anim = LV_MULTANIM_SCALE;
            break;
        case TLV_ANIM_TRANS_DRAG:
            target_anim = LV_MULTANIM_TURN;
            break;
        default:
            break;
        }

        if (NULL == p_tlv->multanim)
            p_tlv->multanim = lv_multanim_create(p_tlv->multlist);
        if (target_anim != lv_multanim_set_type(p_tlv->multanim, target_anim))
        {
            /*For types that use mask animations, the corresponding mask resources need to be loaded and released when switching out*/
#if defined(SOLUTION_RES_USING_NAND) || defined(EX_RES_USING_FILE_MODE)
            if (LV_MULTANIM_FADE == target_anim || LV_MULTANIM_OPEN == target_anim)
            {
                if (NULL == p_tlv->mask_l)
                    p_tlv->mask_l = lv_multanim_create_mask(APP_GET_IMG_FROM_APP(trans_anim, img_mask_left));
                if (NULL == p_tlv->mask_r)
                    p_tlv->mask_r = lv_multanim_create_mask(APP_GET_IMG_FROM_APP(trans_anim, img_mask_right));
                lv_multanim_set_mask(p_tlv->multanim, p_tlv->mask_l, p_tlv->mask_r);
            }
            else
            {
                if (p_tlv->mask_l)
                    lv_multanim_free_mask(p_tlv->mask_l);
                if (p_tlv->mask_r)
                    lv_multanim_free_mask(p_tlv->mask_r);
                p_tlv->mask_l = NULL;
                p_tlv->mask_r = NULL;
            }
#else
            lv_multanim_set_mask(p_tlv->multanim, APP_GET_IMG_FROM_APP(trans_anim, img_mask_left), APP_GET_IMG_FROM_APP(switch_anim, img_mask_right));
#endif
            /*For scaling animations, it is necessary to configure appropriate zoom parameters*/
            if (LV_MULTANIM_ZOOM == target_anim)
                lv_multanim_set_zoom(p_tlv->multanim, APP_TRANS_ANIM_ZOOM_NONE, APP_TRANS_ANIM_ZOOM_NONE >> 1);
            else if (LV_MULTANIM_3D == target_anim)
                lv_multanim_set_zoom(p_tlv->multanim, APP_TRANS_ANIM_ZOOM_NONE + 2, APP_TRANS_ANIM_ZOOM_NONE * 0.7f);
            else if (LV_MULTANIM_SCALE == target_anim)
                lv_multanim_set_zoom(p_tlv->multanim, APP_TRANS_ANIM_ZOOM_NONE + 2, APP_TRANS_ANIM_ZOOM_NONE + 2);
            else
                lv_multanim_set_zoom(p_tlv->multanim, APP_TRANS_ANIM_ZOOM_NONE, APP_TRANS_ANIM_ZOOM_NONE);
        }

        if (LV_MULTANIM_ZOOM != target_anim)
            lv_obj_center(item->snapshot);
        int32_t proc = (offset << 10) / LV_HOR_RES_MAX;
        if (anim_type == TLV_ANIM_TYPE_FIRST)
        {
            //animation type 1:
            if (offset_abs <= (LV_HOR_RES_MAX >> 1))
            {
                if (offset_abs <= (LV_HOR_RES_MAX >> 2))
                {
                    if (LV_MULTANIM_ZOOM != target_anim)
                        lv_img_set_zoom(item->snapshot, APP_TRANS_ANIM_ZOOM_NONE);
                    lv_multanim_set_major_img(p_tlv->multanim, item->snapshot);
                }
                if (item->snapshot == lv_multanim_get_minor_img(p_tlv->multanim))
                    proc = proc > 0 ? (proc - 1024) : (proc + 1024);
                lv_multanim_set_process(p_tlv->multanim, proc);
            }
            else
            {
                lv_obj_move_background(item->snapshot);
                lv_multanim_set_minor_img(p_tlv->multanim, item->snapshot);
            }
        }
        else
        {
            if (offset_abs <= (LV_HOR_RES_MAX >> 1))
            {
                lv_obj_center(item->snapshot);
                lv_multanim_set_major_img(p_tlv->multanim, item->snapshot);
                lv_multanim_set_process(p_tlv->multanim, proc);
            }
            else
            {
                lv_obj_move_background(item->snapshot);
                lv_multanim_set_minor_img(p_tlv->multanim, item->snapshot);
            }
        }
    }
    if (item->element)
    {
        lv_obj_align(item->element, LV_ALIGN_CENTER, offset, 0);
    }

}

4、暂停流程

//1.删除所有items
lv_multlist_on_pause(g_tlv->multlist);
//2.删除节点info信息
lv_multlist_remove_info_all(g_tlv->multlist);
//3.删除编码器
lv_multlist_disable_encoder(g_tlv->multlist);

5、销毁流程

//1、框架自动删除

5、Demo实现

Demo App位于solution\examples\_app_demo\application\multlist,包含了multlist典型应用场景,案例主要介绍了水平和竖直方向两种类别、常规滑动列表以及按页滑动方式的实现,之外对于复杂的场景需要用到的自定义刷新回调的情况也有案例。
1、普通列表显示方式,可带有贝塞尔变形的。 变形后点击事件可按区域识别。参考代码solution\examples\_app_demo\application\multlist\demo_multlist_list.c
水平方向滑动场景

fishy

竖直方向滑动场景

fishy

2、按页翻转方式,参考代码solution\examples\_app_demo\application\multlist\demo_multlist_page.c 水平方向翻页场景

fishy

竖直方向翻页场景

fishy

3、主要应用于小图标的切换显示,需自定义图片的透明度,缩放系数等,参考代码solution\examples\_app_demo\application\multlist\demo_multlist_anim.c
自定义水平方向场景

fishy

自定义竖直方向场景

fishy

4、对话场景,适用于节点信息动态添加和删除的情况,参考代码solution\examples\_app_demo\application\multlist\demo_multlist_dialog.c

fishy

四、注意事项

1、在进行功能划分时,将有关的功能以插件的形式进行了封装,便于逻辑功能的独立性。由于插件与multlist通过相应的事件交互,插件是配配置的,即可根据实际场景,对某些插件进行使能。multist为所有插件的主体,插件如下:
1) lvsf_multswipe:主要负责滑动删除的功能,包括左滑删除和上滑删除,以及两种内置的删除风格样式
2) lvsf_multedge:主要实现侧边栏、上下拉等。类似于自动显示和隐藏的悬浮窗口
3) lvsf_scrollbar:主要实现进度条功能,包括圆形和长条形。

2、回调函数主要有3个需要注意 element的动态创建与删除,创建时的返回值为item->element的元素,删除回调为element元素在删除前调用,回调里不能删除element元素,该回调的主要目的是进行数据订阅的退订、上层应用的通知等。 typedef lv_obj_t *(*lv_multlist_create_item_cb)(lv_obj_t *parent, lv_multlist_item_t *item); typedef void (*lv_multlist_remove_item_cb)(lv_multlist_item_t *);

info节点信息的删除回调,考虑到添加info函数lv_multlist_add_info中的info和user_data有可能是动态分配的情况,所以在item节点被删除时,需对该内存进行释放回收,由于该接口在调用lv_multlist_remove_item_cb之后,所以在该回调函数处理过程中element已经释放,不能访问。
`lv_multlist_item_t *lv_multlist_add_info(lv_obj_t *multlist, lv_coord_t w, lv_coord_t h, void *info, void *user_data);`
`typedef void (*lv_multlist_delete_info_cb)(lv_multlist_item_t *);`

3、通过lv_multlist_add_info(menu, LV_HOR_RES_MAX, BG_BTN_HEIGHT, (void *)app, NULL);添加的节点信息包含了item的宽度和高度,对于某些应用场景事先不能确认的,可以预估item的宽高。该值的偏差会影响对齐的位置,以及进度条的进度偏差。

4、由于multlist默认会保持之前的位置,所以在删除所有节点信息后位置信息还保持之前的pos。如果再次调用对齐时,会时一次的移动位置超过最大的偏移,有可能item显示不全。所以在清楚节点前,需先将位置置到指定pos。