LVGL v8 可以实现真正的循环滚动,相关方法请自行百度,这里只是一种基于 v7.11.0 的实现方法
折腾了几天,还是把按键切换显示对象的形式换回了伪循环滚动,现将踩坑记录在此。
要想达到每个对象显示时居于屏幕中心、并且能循环滚动,就需要解决两个问题:
1. 实现一个将指定对象滚动到屏幕中心的函数
只用 lv_page_focus
不能实现 2 个以上对象居中显示的效果,但只有 2 个对象时却可以
- 替代方案 1
- 聚焦到第 2 个对象后删除第 1 个对象,但实测发现会导致动画丢失。
- 如果将删除操作放在动画结束的回调函数中,则会出现更多奇怪的 bug
- 替代方案 2
- 在对象之间插入 1 条线作为聚焦对象
- 实测发现对线聚焦后,线不会刚好在屏幕边沿出现,而是会在边沿靠上一点的位置,因此还是不行
2. 实现能循环滚动的函数
- 替代方案 1
- 循环删除和创建对象
- 如前所述,会导致动画丢失
- 替代方案 2
- 用 tileview
- tileview 无法仅用代码来选择聚焦哪个对象,必须要求屏幕是触屏,因此该方案无效
曲线解法:伪循环滚动
- 使用
lv_page_focus
,不同的是将卡片高度设置为屏幕高度、inner_pad 和 vertical_pad 都设置为 0 - 优点
- 聚焦到对应卡片时显示效果就是卡片刚好居中,并且不会丢失动画
- 肉眼效果就是卡片在循环滚动
- 缺点
- 卡片之间的间隔没有了
- 卡片实际没有滚动循环
下面是相关实现代码(不是完整代码):
//容器变量
lv_obj_t *cont_kitchen;//厨房节点容器
lv_obj_t *cont_livingRoom;//客厅节点容器
lv_obj_t *cont_hallway;//过道节点容器
lv_obj_t *cont_bedRoom;//卧室节点容器
//容器数组,用来循环切换焦点
static lv_obj_t *cards[CARD_NUM];
//卡片id
static int card_id = 0;
void SystemTab_Create(lv_obj_t* parent){
/************配置页面样式********/
lv_page_set_scrl_layout(parent,LV_LAYOUT_COLUMN_MID);
lv_obj_set_style_local_pad_ver(parent,LV_PAGE_PART_SCROLLABLE,LV_STATE_DEFAULT,0);
lv_obj_set_style_local_pad_inner(parent,LV_PAGE_PART_SCROLLABLE,LV_STATE_DEFAULT, 0);
lv_obj_add_style(parent,LV_PAGE_PART_BG,&style_font_14);//14号中文字体
lv_page_set_scrlbar_mode(parent,LV_SCRLBAR_MODE_OFF);//关闭滚动条
/************创建各个节点对应容器********/
cont_kitchen = cont_kitchen_create(parent);
cont_livingRoom = cont_livingRoom_create(parent);
cont_hallway = cont_hallway_create(parent);
cont_bedRoom = cont_bedRoom_create(parent);
//将各容器(卡片)保存到数组中,方便后续循环切换
cards[0] = cont_kitchen;
cards[1] = cont_livingRoom;
cards[2] = cont_hallway;
cards[3] = cont_bedRoom;
}
//每触摸一次按键就会调用该函数
void SwitchCard(void){
card_id++;
if(card_id >= CARD_NUM)
card_id = 0;
lv_page_focus(tab_SystemState,cards[card_id],LV_ANIM_ON);
}
void ReadButton(lv_task_t *task){
if(button_touched[BUTTON_SWITCH_TAB] == true){
SwitchTab();
button_touched[BUTTON_SWITCH_TAB] = false;
}
if(button_touched[BUTTON_SCROLL_PAGE] == true){
SwitchCard();
button_touched[BUTTON_SCROLL_PAGE] = false;
}
}
运行效果: