平铺应用
简介
平铺应用是挂载在主应用框架中的一个特殊的应用,包含了表盘、上下快捷页面、左右子应用
支持最少一个子应用,没有最大数量限制(视内存情况而定)
支持切换动画平移、缩放、弧形旋转,水平3d翻转、绕Y轴翻转,以及用户自定义动画
他的调度与主应用框架类似,通过msg_handle进行,msg中的参数是该应用的节点信息,其结构是”tlv_node_t“
注:有的用户也习惯将平铺应用称作一级页面
注册一个平铺应用
TLV_REGISTER(priority, id, name, thumb_img, ptr_size)
priority : 应用优先级,应用按照优先级从高(数值小)到低排列,平铺应用的顺序可以动态调整,如编辑页面拖动排序。
id : 应用名字,字符串,框架调度该应用时使用,需要保证在平铺框架中的唯一性
name : 应用显示标题,多语言字符串,仅作显示用
thumb_img : 应用缩略图,编辑时使用
ptr_size : 应用全局内存大小,该内存由框架申请释放,页面可以直接使用
平铺应用的启动、销毁流程(1.0)
启动、销毁
内部调度
动画配置
平铺应用实现(2.X)


平铺页面主要包含了四部分内容:
TLV应用管理 主要提供显示设定的TLV应用和表盘,并可通过长按进入TLV编辑页面,该界面提供TLV的添加与删除以及换位操作。
表盘管理 主要提供表盘的编辑与选择,选择指定的表盘作为TLV应用,同时提供了六扇门表盘选择页面。
辅助窗口 主要包含下拉消息框、上拉堆叠菜单、右滑侧边栏以及快捷页面,所有辅助框均通过lv_multegde控件分装了拖拽交互实现流程,使用时只需关注于应用的具体内容,方便快速开发。
切换动画 动画主要包含了TLV滑动切换动画的配置,上下拉页面的切换动画等。
注意事项
帧率
平铺页面是同时存在左中右三个子应用,为了实现较高的刷新速率,一般建议:
每个子应用尽量不要做成大长页,在满足设计需求的条件下,页面尽可能简单
对于某些确实需要较为复杂设计的场景,考虑使用进场动画,把复杂的元素的初始化延后,既提高了帧率又增加了页面的动感
平铺页面一定要禁止读写flash以及使用delay操作,涉及到历史数据的可以提前把数据读取出来保存在内存中
不推荐直接使用尺寸较大的圆或者弧,可以使用图片代替,若图片无法满足则推荐使用拍照功能
由于平铺页面挂载了太多的子页面,启动该应用时需要初始化太多内容,严重影响应用切换速度,因此方案提供快速初始化选项,
在config中使能’APP_TILEVIEW_INIT_OPTIMIZE‘即可
状态机差异
需要注意平铺应用的状态机切换与普通应用有差异,普通应用的状态机是从start->resume->pause->stop顺序切换,但是平铺应用的状态机可以是:
start->resume->pause->stop
start->pause->stop
start->stop
这种设计是为了提高平铺应用的状态切换效率,省去中间非必要过程,因此在设计平铺应用时,需要考虑2、3场景的兼容
示例
创建一个活动记录应用,由于该页面有尺寸较大的进度圈,因此使用进场动画,以提高帧率
static void on_start(void *param)
{
/*获取该应用的parent obj*/
lv_obj_t *parent = TLV_GET_NODE_PARENT;
/*获取框架申请的全局内存*/
p_activity = TLV_GET_NODE_MEM_PTR;
LV_ASSERT_NULL(p_activity);
/*创建背景图片*/
lv_obj_t *bg_img = lv_img_create(parent);
lv_img_set_src(bg_img, APP_GET_IMG(img_activity_bg_tlv));
lv_obj_center(bg_img);
lv_obj_add_flag(bg_img, LV_OBJ_FLAG_EVENT_BUBBLE);
/*创建一个背景obj,并且设置全透明,其他的子控件均创建在该obj上面*/
lv_obj_t *bg_cont = lv_obj_create(bg_img);
lv_obj_remove_style_all(bg_cont);
lv_obj_set_size(bg_cont, 400, 210);
lv_obj_set_style_bg_color(bg_cont, LV_COLOR_YELLOW, LV_PART_MAIN);
lv_obj_set_style_bg_opa(bg_cont, 0, LV_PART_MAIN);
lv_obj_refr_size(bg_cont);
lv_obj_align(bg_cont, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_refr_pos(bg_cont);
lv_obj_add_flag(bg_cont, LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_clear_flag(bg_cont, LV_OBJ_FLAG_SCROLLABLE);
}
static void on_resume(void *param)
{
/*初始化其他子控件*/
app_activity_init(0);
/*启动一个进场动画,将arc页面的初始化放在该动画中,既提高帧率又增加页面的动感*/
lv_anim_t n_anim;
lv_anim_init(&n_anim);
lv_anim_set_values(&n_anim, 0, 1024);
lv_anim_set_time(&n_anim, 5000);
lv_anim_set_exec_cb(&n_anim, arc_anim_cb);
lv_anim_set_repeat_count(&n_anim, 500);
lv_anim_set_var(&n_anim, p_activity);
lv_anim_start(&n_anim);
}
static void on_pause(void *param)
{
/*删除页面上的动画,防止页面停止时动画还在继续跑引发异常*/
for (uint16_t i = 0; i < 3; i++)
{
lv_anim_del(&p_activity->arc_arr[i], NULL);
}
}
static void on_stop(void *param)
{
/*指针变量置空*/
p_activity = NULL;
}
/*注册一个活动记录的平铺应用*/
TLV_REGISTER(APP_PRIO_ACTIVITY, tlv_activity, app_get_strid(key_tlv_activity, "activity"), img_activity_thum, sizeof(app_activity_t));
如何删除一个平铺应用
typedef struct
{
tlv_desc_t desc;
lv_obj_t *scr; /**< tileview application parent obj */
void *mem_ptr; /**< tileview application global memory pointer */
uint32_t mem_size; /**< tileview application global memory size */
void *user_data; /**< tileview application user data */
rt_list_t list; /**< list link */
tlv_state_t state; /**< application's state */
bool installed; /**< application weather has been installed, true : installed */
bool updated; /**< information whether has been updated, true : updated and will be write to flash when power off
} tlv_node_t;
节点的删除只需将对应节点installed置为false,在读取显示时,会跳过该节点的显示,需要注意删除某个平铺应用时,该应用一定不能处在运行状态。
如何编辑(排序)平铺应用
排序tlv方法主要思路调整tlv链表的节点顺序。可参看wf_edit_proc.c
void tlv_edit_drage_item_cb(lv_event_t *e)
{
lv_obj_t *snapshot = lv_event_get_current_target(e);
lv_obj_t *multlist = lv_obj_get_parent(snapshot);
lv_event_code_t code = lv_event_get_code(e);
//...
if (LV_EVENT_RELEASED == code)
{
//...
rt_list_t *list = tlv_list_get();
if (NULL == item_ref)
{
//需要调整的节点需调整到链表的最后面,只需将移除节点后,在添加到最后面
tlv_node_t *node = (tlv_node_t *)item->info;
rt_list_remove(&node->list);
rt_list_insert_before(list, &node->list);
}
else
{
//需要节点到相关节点的前面,只需删除该节点后在插入该节点前面。
tlv_node_t *node = (tlv_node_t *)item->info;
tlv_node_t *node_ref = (tlv_node_t *)item_ref->info;
rt_list_remove(&node->list);
rt_list_insert_before(&node_ref->list, &node->list);
}
//开启multlist调整动画
lv_multlist_item_move_before(multlist, item, item_ref, true);
item->major_pos = item->org_x;
int32_t target_x = lv_multlist_get_focus_pos(multlist, LV_MULTLIST_ALIGN_CENTER, item);
item->anim_pos_start = pos_x + snapshot->coords.x1 - (item->org_w >> 1);
lv_multlist_anim(item, 0, 1024, 300, wf_edit_recover_anim_exe, wf_edit_recover_anim_ready, NULL);
lv_multlist_anim(multlist, pos_x, target_x, 300, (lv_anim_exec_xcb_t)lv_multlist_set_pos, NULL, NULL);
edit->drage_item = NULL;
edit->focus_item = item;
}
//...
}
