多边形菜单
多边形菜单是一个用于显示多边形布局的菜单。通过改变不同的
形状
, 可以实现不同风格的多边形菜单。
属性
Property | Description |
---|---|
Menu | 菜单项列表 |
Shape | 形状,六边形和正方形 |
Load Screen | 加载页面,启用后,在菜单项处于 STATUS_ZOOM_4 状态时,点击菜单项会加载到菜单项所关联的页面 |
Duration | 加载动画持续时间 |
Delay | 加载动画延迟时间 |
Anim Type | 加载动画类型 |
Is Clear | 加载新屏幕前释放当前屏幕内存, 相当于 lv_obj_clear(obj) |
Is Del | 加载完后删除当前页面, 相当于 lv_obj_del(obj) |
Push Satck | 当前页面是否压入页面栈 |
样式属性
菜单控件默认会使用 lv_polygonmenu_item_transform_cb
位置变换回调函数处理菜单项的坐标、Zoom 等属性。如果 位置变换
填写了自定义的回调函数名,则使用自定义的位置变换回调函数。
- 默认位置变换回调函数支持的样式属性
Property | Description |
---|---|
Radius | 球体半径 |
R Corner | 球体圆角 |
Distortion Coeff | 畸变系数 |
- 自定义位置变换回调函数支持的样式属性
Property | Description |
---|---|
Nop1 | 自定义属性1 |
Nop2 | 自定义属性2 |
Nop3 | 自定义属性3 |
Nop4 | 自定义属性4 |
样式
Style | Part | Description |
---|---|---|
Padding Left | Main | 左内边距 |
Padding Right | Main | 右内边距 |
Padding Top | Main | 上内边距 |
Padding Bottom | Main | 下内边距 |
Padding Row | Items | 行内边距 |
Padding Column | Items | 列内边距 |
使用
- 菜单配置
多边形菜单控件默认处于 STATUS_ZOOM_2
状态时,点击菜单项时,会自动放大到 STATUS_ZOOM_4
状态。所以在配置菜单项时,不能像是其他菜单控件那样,通过配置菜单项的事件,来实现点击菜单项时,执行加载页面。
如果需要实现点击菜单项来加载页面,可以通过配置菜单项的 关联页面
来为菜单项绑定页面,在控件属性启用 加载页面
选项,这样点击菜单项时,会自动加载页面。
在下面的菜单配置中,为菜单项都配置了 关联页面
。

六边形
- 控件属性
启用 加载页面
选项后,注意需启用 入页面栈
选项,这样在其他页面点击按钮后,可以返回到菜单页面。

- 关联页面配置
分别创建了 page1
、page2
、page3
、page4
四个页面,然后在其页面加了按钮,用于点击后 页面出栈
返回菜单页面。

- 仿真

编码器滚动加载页面
为了实现编码器滚动,能控制缩放菜单项,当放大到最大状态,能够自动切换到菜单项所关联的页面,为此需要在 custom
目录下实现这个功能。
增加 indev_encode.h
和 indev_encode.c
文件,目的是能接收编码器事件,并处理编码器事件。
- indev_encode.h
#ifndef INDEV_ENCODE_H
#define INDEV_ENCODE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "lvgl.h"
typedef void (*indev_encode_roll_cb_t)(bool up);
void indev_encode_init();
void indev_encode_set_roll_cb(indev_encode_roll_cb_t cb);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif
- indev_encode.c
#include "indev_encode.h"
#include "lv_drivers/sdl/sdl.h"
#include "gui_guider.h"
static lv_indev_drv_t indev_encode_drv;
static lv_indev_t * indev;
static indev_encode_roll_cb_t roll_cb;
static void indev_read_timer_cb(lv_timer_t * timer);
static void indev_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_proc_reset_query_handler(lv_indev_t * indev);
void indev_encode_init()
{
lv_indev_drv_init(&indev_encode_drv);
indev_encode_drv.type = LV_INDEV_TYPE_ENCODER;
#ifdef USE_GUIBUILDER_SIMULATOR
indev_encode_drv.read_cb = sdl_mousewheel_read;
#else
indev_encode_drv.read_cb = sdl_mousewheel_read; // TODO: 需要修改为设备自定义的拨盘读取函数
#endif
indev = lv_indev_drv_register(&indev_encode_drv);
if(indev->driver->read_timer) {
lv_timer_del(indev->driver->read_timer);
}
indev->driver->read_timer = lv_timer_create(indev_read_timer_cb, LV_INDEV_DEF_READ_PERIOD, indev);
}
void indev_encode_set_roll_cb(indev_encode_roll_cb_t cb)
{
roll_cb = cb;
}
static void indev_read_timer_cb(lv_timer_t * timer)
{
lv_indev_data_t data;
if(indev->driver->disp == NULL)
return;
indev_proc_reset_query_handler(indev);
if(indev->proc.disabled)
return;
/*Read the data*/
_lv_indev_read(indev, &data);
/*The active object might be deleted even in the read function*/
indev_proc_reset_query_handler(indev);
indev->proc.state = data.state;
/*Save the last activity time*/
if(indev->proc.state == LV_INDEV_STATE_PRESSED) {
indev->driver->disp->last_activity_time = lv_tick_get();
}
indev_proc(indev, &data);
}
static void indev_proc(lv_indev_t * i, lv_indev_data_t * data)
{
if(data->state == LV_INDEV_STATE_PRESSED && i->proc.wait_until_release) return;
if(i->proc.wait_until_release) {
i->proc.wait_until_release = 0;
i->proc.pr_timestamp = 0;
i->proc.long_pr_sent = 0;
i->proc.types.keypad.last_state = LV_INDEV_STATE_RELEASED; /*To skip the processing of release*/
}
/*Save the last keys before anything else.
*They need to be already saved if the function returns for any reason*/
lv_indev_state_t last_state = i->proc.types.keypad.last_state;
i->proc.types.keypad.last_state = data->state;
i->proc.types.keypad.last_key = data->key;
if(data->state == LV_INDEV_STATE_RELEASED && last_state == LV_INDEV_STATE_PRESSED) {
return;
}
if(data->enc_diff != 0) {
// -1 :往上拨 1 :往下拨
bool up = data->enc_diff < 0;
if(roll_cb) {
roll_cb(up);
}
}
}
/**
* Process a new point from LV_INDEV_TYPE_BUTTON input device
* @param i pointer to an input device
* @param data pointer to the data read from the input device
* Reset input device if a reset query has been sent to it
* @param indev pointer to an input device
*/
static void indev_proc_reset_query_handler(lv_indev_t * indev)
{
if(indev->proc.reset_query) {
indev->proc.types.pointer.act_obj = NULL;
indev->proc.types.pointer.last_obj = NULL;
indev->proc.types.pointer.scroll_obj = NULL;
indev->proc.long_pr_sent = 0;
indev->proc.pr_timestamp = 0;
indev->proc.longpr_rep_timestamp = 0;
indev->proc.types.pointer.scroll_sum.x = 0;
indev->proc.types.pointer.scroll_sum.y = 0;
indev->proc.types.pointer.scroll_dir = LV_DIR_NONE;
indev->proc.types.pointer.scroll_throw_vect.x = 0;
indev->proc.types.pointer.scroll_throw_vect.y = 0;
indev->proc.types.pointer.gesture_sum.x = 0;
indev->proc.types.pointer.gesture_sum.y = 0;
indev->proc.reset_query = 0;
}
}
/**
* Checks if the reset_query flag has been set. If so, perform necessary global indev cleanup actions
* @param proc pointer to an input device 'proc'
* @return true if indev query should be immediately truncated.
*/
static bool indev_reset_check(_lv_indev_proc_t * proc)
{
// if(proc->reset_query) {
// indev_obj_act = NULL;
// }
return proc->reset_query ? true : false;
}
在 custom.c
文件中,初始化编码器,并实现 indev_encode_set_roll_cb
函数。
// 编码器滚动回调函数,识别到是多边形菜单所在页面时,根据编码器滚动方向,放大或缩小多边形菜单
static void indev_encode_roll_cb(bool up)
{
gui_scr_t * act_scr = gui_scr_get_act();
// 注意将 GUI_SCREEN_POLYGONMENU 替换为实际的多边形菜单所在页面
if(act_scr->id == GUI_SCREEN_POLYGONMENU) {
lv_ui_polygonmenu * ui_polygonmenu = (lv_ui_polygonmenu *)ui_get_scr_ptr(&guider_ui, GUI_SCREEN_POLYGONMENU);
if(up) {
lv_polygonmenu_zoom_in(ui_polygonmenu->polygonmenu_polygonmenu_1);
}
else {
lv_polygonmenu_zoom_out(ui_polygonmenu->polygonmenu_polygonmenu_1);
}
}
}
void custom_init(lv_ui * ui)
{
indev_encode_init();
indev_encode_set_roll_cb(indev_encode_roll_cb);
}
- 仿真

- 正方形仿真
