平铺应用

简介

  1. 平铺应用是挂载在主应用框架中的一个特殊的应用,包含了表盘、上下快捷页面、左右子应用

  2. 支持最少一个子应用,没有最大数量限制(视内存情况而定)

  3. 支持切换动画平移、缩放、弧形旋转,水平3d翻转、绕Y轴翻转,以及用户自定义动画

  4. 他的调度与主应用框架类似,通过msg_handle进行,msg中的参数是该应用的节点信息,其结构是”tlv_node_t“

注:有的用户也习惯将平铺应用称作一级页面

注册一个平铺应用

TLV_REGISTER(priority, id, name, thumb_img, ptr_size)
priority    : 应用优先级,应用按照优先级从高(数值小)到低排列,平铺应用的顺序可以动态调整,如编辑页面拖动排序
id          : 应用名字,字符串,框架调度该应用时使用,需要保证在平铺框架中的唯一性
name        : 应用显示标题,多语言字符串,仅作显示用
thumb_img   : 应用缩略图,编辑时使用
ptr_size    : 应用全局内存大小,该内存由框架申请释放,页面可以直接使用

平铺应用的启动、销毁流程(1.0)

  1. 启动、销毁

  2. 内部调度

  3. 动画配置

平铺应用实现(2.X)

fishy fishy

平铺页面主要包含了四部分内容:

  1. TLV应用管理 主要提供显示设定的TLV应用和表盘,并可通过长按进入TLV编辑页面,该界面提供TLV的添加与删除以及换位操作。

  2. 表盘管理 主要提供表盘的编辑与选择,选择指定的表盘作为TLV应用,同时提供了六扇门表盘选择页面。

  3. 辅助窗口 主要包含下拉消息框、上拉堆叠菜单、右滑侧边栏以及快捷页面,所有辅助框均通过lv_multegde控件分装了拖拽交互实现流程,使用时只需关注于应用的具体内容,方便快速开发。

  4. 切换动画 动画主要包含了TLV滑动切换动画的配置,上下拉页面的切换动画等。

注意事项

帧率

平铺页面是同时存在左中右三个子应用,为了实现较高的刷新速率,一般建议:

  1. 每个子应用尽量不要做成大长页,在满足设计需求的条件下,页面尽可能简单

  2. 对于某些确实需要较为复杂设计的场景,考虑使用进场动画,把复杂的元素的初始化延后,既提高了帧率又增加了页面的动感

  3. 平铺页面一定要禁止读写flash以及使用delay操作,涉及到历史数据的可以提前把数据读取出来保存在内存中

  4. 不推荐直接使用尺寸较大的圆或者弧,可以使用图片代替,若图片无法满足则推荐使用拍照功能

  5. 由于平铺页面挂载了太多的子页面,启动该应用时需要初始化太多内容,严重影响应用切换速度,因此方案提供快速初始化选项,

在config中使能’APP_TILEVIEW_INIT_OPTIMIZE‘即可

状态机差异

需要注意平铺应用的状态机切换与普通应用有差异,普通应用的状态机是从start->resume->pause->stop顺序切换,但是平铺应用的状态机可以是:

  1. start->resume->pause->stop

  2. start->pause->stop

  3. 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;
    }
    //...
}
fishy