在实际应用中,可能会使用roller控件实现时间选择功能,选项列表只有24小时的时候,界面显示是正常的。但当选项列表是60分钟的时候,由于列表过长,显示就会出现问题。如众多帖子描述,只需要在lv_conf.h中打开宏 LV_USE_LARGE_COORD 即可。
虽然解决了显示问题,却发现在roller控件创建的时候耗时严重,尤其是当程序运行在资源有限的嵌入式设备上,问题更加明显,进而导致页面打开卡顿,影响体验。
换一种思路,如果每次只设置5个选项给roller控件,在每次滚动时重新计算并设置选项列表……
#define OPTION_FMT "%02d\n%02d\n%02d\n%02d\n%02d" // 选项列表格式
#define MASTER_INDEX 2 // 列表为5项,中间项索引为2
#define OPTION_LEN 32 // 列表字符串buffer长度
/**
* @brief 选项列表最大值最小值
*/
typedef struct {
int min;
int max;
} roller_range_t;
/**
* @brief 计算选项列表
* @param val 当前选中的值
* @param buf 选项列表字符串buffer
* @param len 选项列表字符串buffer长度
* @param min 控件选项列表最小值
* @param max 控件选项列表最大值
*/
static void calc_roller_option( int val, char* buf, int len, int min, int max )
{
int left1 = val - 1;
int left2 = val - 2;
int right1 = val + 1;
int right2 = val + 2;
int range = max - min + 1;
if ( left1 < min ) {
left1 += range;
}
if ( left2 < min ) {
left2 += range;
}
if ( right1 > max ) {
right1 -= range;
}
if ( right2 > max ) {
right2 -= range;
}
snprintf( buf, len, OPTION_FMT, left2, left1, val, right1, right2 );
return;
}
/**
* @brief roller控件事件回调函数
* @param e
*/
static void roller_event_cb( lv_event_t* e )
{
if ( LV_EVENT_VALUE_CHANGED == lv_event_get_code( e ) ) {
lv_obj_t* obj = lv_event_get_target( e );
roller_range_t* range = (roller_range_t*)(obj->user_data);
char buf[OPTION_LEN] = "\0";
int val = 0;
lv_roller_get_selected_str( obj, buf, OPTION_LEN );
val = atoi( buf );
calc_roller_option( val, buf, OPTION_LEN, range->min, range->max );
lv_roller_set_options( obj, buf, LV_ROLLER_MODE_NORMAL ); // 这里不需要设置无限模式,计算列表时已处理列表循环
lv_roller_set_selected( obj, MASTER_INDEX, LV_ANIM_OFF );
}
return;
}
/**
* @brief 创建roller控件
* @param parent 父窗体
* @param def_val 默认值
* @param min_val 最小值
* @param max_val 最大值
* @return 已创建的roller对象指针
*/
static lv_obj_t* create_roller( lv_obj_t* parent, int def_val, int min_val, int max_val )
{
lv_obj_t* roller = lv_roller_create( parent );
roller_range_t* range = (roller_range_t*)malloc( sizeof( roller_range_t ) );
if ( NULL != range ) {
range->min = min_val;
range->max = max_val;
}
roller->user_data = (void*)range;
char option[OPTION_LEN] = "\0";
calc_roller_option( def_val, option, OPTION_LEN, min_val, max_val );
lv_roller_set_options( roller, option, LV_ROLLER_MODE_NORMAL );
lv_roller_set_selected( roller, MASTER_INDEX, LV_ANIM_OFF );
lv_obj_add_event_cb( roller, roller_event_cb, LV_EVENT_VALUE_CHANGED, NULL );
return roller;
}
/**
* @brief 设置roller当前值
* @param roller 控件对象
* @param val 当前值
*/
static void set_roller_cur_val( lv_obj_t* roller, int val )
{
roller_range_t* range = (roller_range_t*)(roller->user_data);
char buf[OPTION_LEN] = "\0";
calc_roller_option( val, buf, OPTION_LEN, range->min, range->max );
lv_roller_set_options( roller, buf, LV_ROLLER_MODE_NORMAL );
lv_roller_set_selected( roller, MASTER_INDEX, LV_ANIM_OFF );
}
void main( void )
{
lv_obj_t* roller1 = create_roller( lv_scr_act(), 0, 0, 59 );
lv_roller_set_visible_row_count( roller1, 3 );
lv_obj_center( roller1 );
set_roller_cur_val( roller1, 24 );
return;
}
轻松实现超长选项列表的roller控件,不仅分散了创建roller时设置option的耗时,避免页面创建时卡顿,同时也可以不需要 LV_USE_LARGE_COORD 的支持。