multswipe控件¶
1. 使用场景¶
multswipe控件是基于lvgl框架扩展的滑动操作控件,主要为multlist列表项(lv_multlist_item_t)提供滑动交互能力,支持不同样式的滑动操作(如基础滑动、带删除按钮滑动、带扩展图标滑动),核心应用于列表项的滑动删除、滑动触发自定义操作等场景,例如:
列表项滑动超过阈值自动触发删除/自定义处理逻辑;
列表项左滑/上滑露出删除按钮,点击按钮删除列表项;
聚焦状态下的列表项滑动权限控制(仅对齐时允许滑动删除)。
2. 接口介绍¶
2.1 核心数据类型¶
接口函数 |
功能说明 |
参数说明 |
|---|---|---|
lv_multswipe_enable |
启用列表项的拖拽删除功能,为列表项内容添加滑动覆盖层 |
item:multlist的列表项对象;content:需要添加覆盖层的列表项内容对象;style:滑动样式(LV_MULTSWIPE_STYLE_DEFAULT/LV_MULTSWIPE_STYLE_WITH_BTN/LV_MULTSWIPE_STYLE_WITH_EXPAN);返回值:滑动覆盖层对象 |
lv_multswipe_set_process_cb |
设置拖拽过程的回调函数,用于判断滑动边缘作用的列表项 |
item:multlist的列表项对象;process:拖拽过程的回调函数(process_cb类型,入参包含列表项、内容、删除按钮、处理标识);返回值:无 |
lv_multswipe_set_del_btn |
为列表项设置删除按钮(仅对LV_MULTSWIPE_STYLE_WITH_BTN样式生效) |
item:multlist的列表项对象;del_btn:点击触发删除的按钮对象;返回值:无 |
lv_multswipe_set_src |
为列表项设置删除图标资源(仅对LV_MULTSWIPE_STYLE_WITH_EXPAN样式生效) |
item:multlist的列表项对象;del_src:图片资源的指针;返回值:无 |
lv_multswipe_enbale_focus |
设置仅当列表项处于聚焦对齐状态时,启用滑动删除功能 |
item:multlist的列表项对象;en:启用/禁用标识(1启用,0禁用);返回值:无 |
lv_multswipe_set_thres |
设置滑动阈值,列表项聚焦或拖拽超过该范围时触发删除 |
item:multlist的列表项对象;thres_val:阈值数值;返回值:无 |
lv_multswipe_set_springback |
设置列表项可拖拽的最大范围(回弹阈值) |
item:multlist的列表项对象;springback:最大拖拽距离;返回值:无 |
lv_multswipe_set_dir |
设置列表项的拖拽方向 |
item:multlist的列表项对象;dir:拖拽方向(1为正方向,0为负方向);返回值:无 |
3. 使用案例¶
3.1 默认上滑/左滑删除案例¶
当需要使能默认删除方式时,只需再multlist的新建item回调函数中调用lv_multswipe_enable接口即可使能左滑或上滑删除。
lv_obj_t *tlv_edit_create_item(lv_obj_t *parent, lv_multlist_item_t *item)
{
tlv_edit_t *edit = (tlv_edit_t *)lv_obj_get_user_data(parent);
lv_obj_t *item_cont = lv_obj_create(parent);
lv_obj_remove_style_all(item_cont);
lv_obj_set_size(item_cont, item->org_w, item->org_h);
lv_obj_set_style_bg_opa(item_cont, LV_OPA_100, LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(item_cont, LV_COLOR_BLACK, LV_STATE_DEFAULT);
lv_obj_add_flag(item_cont, LV_OBJ_FLAG_PRESS_LOCK | LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_clear_flag(item_cont, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_refr_size(item_cont);
lv_obj_t *item_btn = lv_obj_create(item_cont);
lv_obj_remove_style_all(item_btn);
lv_obj_set_size(item_btn, item->org_w, item->org_h);
lv_obj_set_style_radius(item_btn, 20, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(item_btn, 4, LV_STATE_DEFAULT);
lv_obj_set_style_border_opa(item_btn, LV_OPA_100, LV_STATE_DEFAULT);
lv_obj_set_style_border_color(item_btn, lv_color_make(0x55, 0x55, 0x55), LV_STATE_DEFAULT);
lv_obj_add_flag(item_btn, LV_OBJ_FLAG_PRESS_LOCK | LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_clear_flag(item_btn, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_refr_size(item_btn);
const void *img_src = APP_GET_IMG(tlv_edit_add);
if (item->info)
{
tlv_node_t *node = (tlv_node_t *)item->info;
if ((TLV_ADD_TYPE == edit->type && node->installed) || \
edit->cur_node && (0 == strcmp(edit->cur_node, node->desc.id_str)))
lv_obj_set_style_border_color(item_btn, lv_color_make(0xFF, 0, 0), LV_STATE_DEFAULT);
img_src = node->desc.thumbnail;
//当需要使能默认删除方式时,只需调用lv_multswipe_enable接口使能即可
if (rt_strcmp(node->desc.id_str, "tlv_shortcut") && TLV_ADD_TYPE != edit->type)
item_cont = lv_multswipe_enable(item, item_cont, LV_MULTSWIPE_STYLE_DEFAULT);
}
if (img_src)
{
lv_obj_t *img = lv_img_create(item_btn);
lv_img_set_src(img, img_src);
lv_obj_refr_size(img);
lv_coord_t zoom_w = (item->org_w - 20) * LV_IMG_ZOOM_NONE / lv_obj_get_width(img);
lv_coord_t zoom_h = (item->org_w - 20) * LV_IMG_ZOOM_NONE / lv_obj_get_height(img);
lv_img_set_zoom(img, LV_MIN(zoom_w, zoom_h));
lv_obj_add_flag(img, LV_OBJ_FLAG_PRESS_LOCK | LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_center(img);
}
return item_cont;
}
//注册删除事件回调,用于内存释放、对齐等操作
void tlv_edit_envent_cb(lv_event_t *e)
{
//.......
//去掉无关代码
if (LV_EVENT_SWIPE_DELETE == code)
{
lv_multlist_item_t *item = lv_event_get_param(e);
if (item && item->info)
{
tlv_node_t *tlv_node = (tlv_node_t *)item->info;
tlv_node->installed = false;
//rt_list_remove(&tlv_node->list);
}
if (item && item->snapshot)
{
lv_obj_del(item->snapshot);
item->snapshot = NULL;
}
if ((uint32_t)(item->index + 1) >= lv_multlist_get_info_cnt(multlist))
lv_multlist_focus_near(multlist, 0, false, true);
item = lv_multlist_get_item_by_index(multlist, 0);
if (!item)
{
gui_app_goback();
return;
}
}
}
案例效果展示
3.2 带删除图标样式¶
//multlist元素创建回调接口中调用lv_multswipe_enable,并设置删除回调函数,用于删除图标的创建
static lv_obj_t *sport_create_item_cb(lv_obj_t *parent, lv_multlist_item_t *item)
{
uint32_t item_type = (uint32_t)item->user_data;
lv_obj_t *item_btn = lv_multobj_create(parent);
lv_obj_remove_style_all(item_btn);
lv_obj_set_size(item_btn, item->org_w, item->org_h);
lv_obj_set_style_radius(item_btn, 12, LV_PART_MAIN);
lv_obj_set_style_bg_opa(item_btn, 255, LV_STATE_DEFAULT);
lv_obj_add_flag(item_btn, LV_OBJ_FLAG_SCROLL_CHAIN | LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_clear_flag(item_btn, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_refr_size(item_btn);
if (SPORT_TYPE_ADD_BTN == item_type)
{
lv_obj_set_style_bg_color(item_btn, lv_color_make(0x52, 0x52, 0x48), LV_STATE_DEFAULT);
lv_obj_set_style_radius(item_btn, lv_obj_get_height(item_btn) >> 1, LV_PART_MAIN);
lv_obj_t *add_txt = lv_label_create(item_btn);
lv_ext_set_local_font(add_txt, FONT_TITLE, LV_COLOR_WHITE);
lv_label_set_text(add_txt, app_get_str(key_add_sport, "Add sport"));
lv_obj_align_to(add_txt, item_btn, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(item_btn, sport_add_btn_click_cb, LV_EVENT_SHORT_CLICKED, NULL);
}
else
{
sport_element_t *sport_item = (sport_element_t *)item->info;
lv_obj_set_style_bg_color(item_btn, lv_color_make(0x4E, 0x66, 0x1A), LV_STATE_DEFAULT);
lv_obj_set_style_radius(item_btn, BTN_BG_CORNER, LV_PART_MAIN);
lv_obj_t *sport_icon = lv_img_create(item_btn);
lv_img_set_src(sport_icon, sport_item->src);
lv_obj_refr_size(sport_icon);
lv_obj_refr_pos(sport_icon);
lv_obj_align(sport_icon, LV_ALIGN_TOP_LEFT, 0, 0);
lv_obj_t *sport_name = lv_label_create(item_btn);
lv_ext_set_local_font(sport_name, FONT_TITLE, LV_COLOR_WHITE);
lv_label_set_text(sport_name, app_get_str_from_id(sport_item->txt));
lv_obj_align(sport_name, LV_ALIGN_TOP_LEFT, 10, lv_obj_get_y(sport_icon) + lv_obj_get_height(sport_icon));
lv_obj_refr_size(sport_name);
lv_obj_refr_pos(sport_name);
lv_obj_t *train_type = lv_label_create(item_btn);
lv_ext_set_local_font(train_type, FONT_SUBTITLE, LV_COLOR_WHITE);
lv_label_set_text(train_type, app_get_str(key_free_train, "Free training"));
lv_obj_refr_size(train_type);
lv_obj_align(train_type, LV_ALIGN_TOP_LEFT, 10, lv_obj_get_y(sport_name) + lv_obj_get_height(sport_name));
lv_obj_t *icon = lv_img_create(item_btn);
lv_img_set_src(icon, APP_GET_IMG(img_sport_setting));
lv_obj_refr_size(icon);
lv_obj_align(icon, LV_ALIGN_TOP_RIGHT, -10, 10);
lv_obj_add_flag(icon, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_event_cb(icon, sport_item_more_click_cb, LV_EVENT_SHORT_CLICKED, (void *)sport_item);
lv_obj_add_event_cb(item_btn, sport_item_click_cb, LV_EVENT_SHORT_CLICKED, (void *)sport_item);
lv_multswipe_set_process_cb(item, sport_item_del_proc);
item_btn = lv_multswipe_enable(item, item_btn, LV_MULTSWIPE_STYLE_WITH_BTN);
}
return item_btn;
}
//删除滑动回调函数
void sport_item_del_proc(lv_multlist_item_t *item, lv_obj_t *content, lv_obj_t *del_btn, int32_t offset)
{
if (NULL == del_btn)
{
lv_coord_t content_h = lv_obj_get_height(content);
del_btn = lv_obj_create(item->element);
lv_obj_remove_style_all(del_btn);
lv_obj_set_size(del_btn, SPORT_DEL_BTN_W, content_h);
lv_obj_set_style_radius(del_btn, BTN_BG_CORNER, LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(del_btn, lv_color_make(0x4E, 0x66, 0x1A), LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(del_btn, 255, LV_STATE_DEFAULT);
lv_obj_add_flag(del_btn, LV_OBJ_FLAG_CHECKABLE | LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_clear_flag(del_btn, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_move_background(del_btn);
lv_obj_set_user_data(del_btn, (void *)item);
lv_obj_add_event_cb(del_btn, sport_del_item, LV_EVENT_SHORT_CLICKED, (void *)item);
lv_obj_t *del_img = lv_img_create(del_btn);
lv_img_set_src(del_img, APP_GET_IMG(img_sport_del));
lv_obj_clear_flag(del_img, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_center(del_img);
lv_obj_refr_size(del_btn);
lv_multswipe_set_thres(item, SPORT_DEL_BTN_W + 20);
lv_multswipe_set_springback(item, SPORT_DEL_BTN_W + 10);
lv_multswipe_set_del_btn(item, del_btn);
}
uint16_t offset_bas = LV_ABS(offset);
if (offset_bas > SPORT_DEL_BTN_W + 10)
lv_obj_set_width(del_btn, offset_bas - 10);
else
lv_obj_set_width(del_btn, SPORT_DEL_BTN_W);
lv_obj_set_x(del_btn, LV_HOR_RES_MAX - offset_bas + 10);
lv_coord_t opa = lv_map(LV_ABS(offset), 0, LV_HOR_RES_MAX >> 2, 0, 255);
lv_obj_set_style_bg_opa(del_btn, opa, 0);
lv_obj_t *img = lv_obj_get_child(del_btn, 0);
if (img)
{
lv_obj_set_style_img_opa(img, opa, 0);
lv_obj_center(img);
}
}
案例效果展示
3.3 消息删除样式¶
//multlist元素创建回调接口中调用lv_multswipe_enable,并设置删除回调函数,用于滑动过程的处理
static lv_obj_t *notify_create_item_cb(lv_obj_t *parent, lv_multlist_item_t *item)
{
lv_obj_t *element = NULL;
uint32_t item_type = (uint32_t)item->info;
if (ELEMENT_TYPE_CLEAR_ALL == item_type)
{
element = lv_obj_create(parent);
lv_obj_set_size(element, item->org_w, item->org_h);
lv_obj_set_style_radius(element, 20, 0);
lv_ext_set_local_bg(element, lv_color_hex(0x353535), LV_OPA_100);
lv_obj_add_event_cb(element, notify_del_all_message, LV_EVENT_SHORT_CLICKED, NULL);
lv_obj_t *clear_btn_txt = lv_label_create(element);
lv_ext_set_local_font(clear_btn_txt, FONT_TITLE, LV_COLOR_WHITE);
lv_label_set_text(clear_btn_txt, "Clean all");
lv_obj_align_to(clear_btn_txt, element, LV_ALIGN_CENTER, 0, 0);
}
if (ELEMENT_TYPE_CONTENT == item_type)
{
message_node_t *msg = (message_node_t *)item->user_data;
uint16_t msg_cnt = notify_get_type_message_cnt(msg->type);
element = notify_create_preview(parent, msg, ELEMENT_CONTENT_WIDTH, msg_cnt);
lv_obj_add_event_cb(element, notify_message_details_cb, LV_EVENT_SHORT_CLICKED, (void *)item);
lv_multswipe_set_process_cb(item, notify_draw_del_proc);
element = lv_multswipe_enable(item, element, LV_MULTSWIPE_STYLE_WITH_BTN);
}
if (ELEMENT_TYPE_NO_MESSAGE == item_type)
{
element = lv_obj_create(parent);
lv_obj_remove_style_all(element);
lv_obj_set_size(element, item->org_w, item->org_h);
//lv_ext_set_local_bg(element, LV_COLOR_GRAY, LV_OPA_30);
lv_obj_center(element);
lv_obj_t *txt_lab = lv_label_create(element);
lv_ext_set_local_font(txt_lab, FONT_TITLE, LV_COLOR_WHITE);
lv_label_set_text(txt_lab, "No message.");
lv_obj_center(txt_lab);
}
return element;
}
//滑动过程回调函数
void notify_draw_del_proc(lv_multlist_item_t *item, lv_obj_t *content, lv_obj_t *del_btn, int32_t offset)
{
if (NULL == del_btn)
{
lv_coord_t content_h = lv_obj_get_style_height(content, 0);
del_btn = lv_obj_create(item->element);
lv_obj_remove_style_all(del_btn);
if (0 == lv_obj_get_style_bg_opa(content, 0))
lv_obj_set_size(del_btn, 10, content_h - 27);
else
lv_obj_set_size(del_btn, 10, content_h);
lv_obj_set_style_radius(del_btn, 20, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(del_btn, 0, LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(del_btn, lv_color_hex(0x353535), LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(del_btn, LV_OPA_100, LV_STATE_DEFAULT);
lv_obj_add_flag(del_btn, LV_OBJ_FLAG_CHECKABLE);
lv_obj_clear_flag(del_btn, LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_set_user_data(del_btn, (void *)item);
lv_obj_add_event_cb(del_btn, notify_del_one_item, LV_EVENT_SHORT_CLICKED, (void *)item);
lv_obj_t *del_img = lv_img_create(del_btn);
lv_img_set_src(del_img, APP_GET_IMG(img_delete_gray));
lv_obj_clear_flag(del_img, LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_center(del_img);
lv_multswipe_set_del_btn(item, del_btn);
}
lv_obj_t *del_img = lv_obj_get_child(del_btn, 0);
lv_obj_align(content, LV_ALIGN_CENTER, offset, 0);
#define DEL_BTN_GAP 10
#define DEL_BTN_W_DEF 100
#define DEL_BTN_W_MAX (LV_HOR_RES_MAX>>1)
/*The farthest sliding distance*/
if (offset + DEL_BTN_W_MAX + DEL_BTN_GAP < 0)
{
lv_obj_set_width(del_btn, DEL_BTN_W_MAX);
lv_obj_align_to(del_btn, content, LV_ALIGN_OUT_RIGHT_BOTTOM, DEL_BTN_GAP, 0);
if (del_img)
lv_obj_align(del_img, LV_ALIGN_CENTER, 0, 0);
}
/*Jitter initiation stage*/
else if (offset + DEL_BTN_W_DEF + DEL_BTN_GAP < 0)
{
uint16_t btn_w = -DEL_BTN_GAP - offset;
lv_obj_set_width(del_btn, btn_w);
lv_obj_align_to(del_btn, content, LV_ALIGN_OUT_RIGHT_BOTTOM, DEL_BTN_GAP, 0);
if (del_img)
{
lv_img_set_zoom(del_img, LV_IMG_ZOOM_NONE);
lv_obj_align(del_img, LV_ALIGN_CENTER, 0, 0);
}
}
else
{
lv_obj_set_width(del_btn, DEL_BTN_W_DEF);
lv_obj_align_to(del_btn, content, LV_ALIGN_OUT_RIGHT_BOTTOM, DEL_BTN_GAP, 0);
lv_coord_t zoom = -offset - DEL_BTN_GAP;
zoom = zoom < DEL_BTN_GAP ? 0 : zoom;
zoom = zoom * LV_IMG_ZOOM_NONE / DEL_BTN_W_DEF;
if (del_img)
{
lv_img_set_zoom(del_img, zoom);
lv_obj_align(del_img, LV_ALIGN_CENTER, 0, 0);
}
}
}
案例效果展示
4. 注意事项¶
样式匹配:
lv_multswipe_set_del_btn仅对LV_MULTSWIPE_STYLE_WITH_BTN样式生效;lv_multswipe_set_src仅对LV_MULTSWIPE_STYLE_WITH_EXPAN样式生效;非对应样式调用上述接口无效果。
依赖关系:控件依赖
lvsf_multlist.h,使用前需确保该头文件已包含且LVSF_USE_MULTSIWPE宏定义不为0。聚焦控制:
lv_multswipe_enbale_focus仅在列表项对齐状态下生效,非对齐状态无法启用滑动删除。回调函数:
process_cb回调需自行实现滑动阈值判断、删除逻辑等业务,框架仅提供回调触发能力。方向控制:滑动方向(正/负)需结合实际UI布局定义,建议先测试方向参数对滑动效果的影响。
资源释放:删除列表项时,需确保滑动控件相关对象(如删除按钮、覆盖层)同步释放,避免内存泄漏。