LVGL 拼音输入法(lv_ime_pinyin)使用说明

lv_ime_pinyin 是 LVGL 的拼音输入法组件,用于在 lv_textarea + lv_keyboard 的基础上提供中文拼音输入、候选字选择、英文/中文模式切换,以及可选的 9 键输入模式。

本文以当前工程使用的 LVGL v8 接口为主,源码路径:

sdk/external/lvgl_v8/src/extra/others/ime/lv_ime_pinyin.c
sdk/external/lvgl_v8/src/extra/others/ime/lv_ime_pinyin.h

1. 功能概览

lv_ime_pinyin 不是独立键盘,而是对 lv_keyboard 的输入事件进行接管和扩展:

  • 绑定一个 lv_keyboard

  • 从键盘获取输入字符。

  • 根据输入的拼音查字典,生成候选字。

  • 在键盘上方显示候选字面板。

  • 点击候选字后,把中文字符写入当前 lv_textarea

  • 支持英文模式、26 键拼音模式、9 键拼音模式、9 键数字模式。

典型 UI 结构如下:

父容器/页面
├── lv_textarea     文本输入框
├── lv_keyboard     软键盘
└── lv_ime_pinyin   拼音输入法对象(内部会创建候选字面板 cand_panel)

1.1 显示效果

集成后的典型显示效果如下图所示:

lv_ime_pinyin 显示效果

实际交互表现:

  • 输入框位于页面上半部分,用于显示和编辑文本内容。

  • 键盘固定在页面底部,按键样式由 lv_keyboard 决定。

  • 输入拼音后,候选字面板会显示在键盘上方;未输入拼音或候选为空时,候选面板隐藏。

  • 候选面板中间为候选汉字,点击候选字后会写入当前 lv_textarea

  • 候选面板两侧的 <> 用于候选字翻页。

  • 用于在英文和中文拼音 26 键之间切换;ABCabc 用于大小写/英文键盘切换。

  • pcalendar 编辑页面中,候选面板设置为白色不透明背景、深色文字、高度 36 px,以避免和上方输入内容重叠。

2. 配置开关

使用前需要先启用 LVGL v8,并打开拼音输入法。menuconfig 的完整路径为:menuconfig (Top) SiFli SDK configuration Third party packages LittlevGL2RTT: The LittlevGl gui lib adapter RT-Thread (PKG_USING_LITTLEVGL2RTT) LVGL configuration select LVGL Version. LVGL V8 LVGL V8 configuration Others Enable Pinyin input method (LV_USE_IME_PINYIN)PKG_USING_LITTLEVGL2RTT 默认关闭,启用后 select LVGL Version. 默认选择 LVGL V8;该 SDK 路径在 HCPU、LCPU 和 PC Simulator 工程均可见。

LV_USE_IME_PINYIN 无直接 depends on,默认关闭,启用后会自动选择 LV_USE_KEYBOARD,无需手动设置键盘宏。若项目直接维护 lv_conf.h,则可通过以下定义打开该功能;menuconfig 配置与 lv_conf.h 只选一种方式维护,避免相互覆盖。

2.1 必选配置

#define LV_USE_IME_PINYIN 1

2.2 可选配置

以下选项都位于同一路径的 Others 子菜单中;打开 LV_USE_IME_PINYIN 后才会显示。LV_IME_PINYIN_USE_DEFAULT_DICT 默认开启,LV_IME_PINYIN_CAND_TEXT_NUM 默认值为 6LV_IME_PINYIN_USE_K9_MODE 默认开启,LV_IME_PINYIN_K9_CAND_TEXT_NUM 默认值为 3,且依赖 LV_IME_PINYIN_USE_K9_MODE。这些配置没有 HCPU/LCPU 或 SoC 专用限制。

#define LV_IME_PINYIN_USE_DEFAULT_DICT 1
#define LV_IME_PINYIN_CAND_TEXT_NUM 6
#define LV_IME_PINYIN_USE_K9_MODE 1
#define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3

说明:

配置项

说明

LV_IME_PINYIN_USE_DEFAULT_DICT

是否使用内置拼音词库。若设为 0,必须调用 lv_ime_pinyin_set_dict() 设置自定义词库后再使用。

LV_IME_PINYIN_CAND_TEXT_NUM

26 键拼音模式下候选字面板一次显示的候选按钮数量,默认 6。小屏可适当减小。

LV_IME_PINYIN_USE_K9_MODE

是否启用 9 键输入模式。

LV_IME_PINYIN_K9_CAND_TEXT_NUM

9 键模式候选拼音数量,默认 3。

3. 主要接口

头文件:

#include "lv_ime_pinyin.h"

3.1 创建输入法对象

lv_obj_t * lv_ime_pinyin_create(lv_obj_t * parent);

创建拼音输入法对象。创建后对象本身默认隐藏,但会在内部创建候选字面板 cand_panel

参数:

  • parent:输入法对象的父对象。通常传键盘和输入框所在的页面/弹窗容器。

返回值:

  • lv_obj_t *:拼音输入法对象句柄。

3.2 绑定键盘

void lv_ime_pinyin_set_keyboard(lv_obj_t * obj, lv_obj_t * kb);

把输入法对象绑定到一个 lv_keyboard

调用后输入法会:

  • 保存键盘对象。

  • 把输入法对象和候选面板移动到键盘的父容器下。

  • 移除键盘默认事件 lv_keyboard_def_event_cb

  • 给键盘注册拼音输入法事件处理函数。

  • 将候选面板对齐到键盘上方。

注意:绑定前应先创建 lv_keyboard,并建议先调用 lv_keyboard_set_textarea(kb, ta) 指定输入框。

3.3 设置词库

void lv_ime_pinyin_set_dict(lv_obj_t * obj, lv_pinyin_dict_t * dict);

设置拼音词库。

词库结构:

typedef struct {
    const char * const py;     /* 拼音,例如 "ni" */
    const char * const py_mb;  /* 候选汉字字符串,例如 "你尼呢" */
} lv_pinyin_dict_t;

自定义词库示例:

static lv_pinyin_dict_t user_dict[] = {
    { "ni",  "你尼呢" },
    { "hao", "好号浩" },
    { "shi", "是时事市" },
    { NULL,   NULL }     /* 必须使用 NULL 作为结束项 */
};

lv_ime_pinyin_set_dict(ime, user_dict);

如果 LV_IME_PINYIN_USE_DEFAULT_DICT 为 1,创建输入法时会自动加载内置词库;客户只需要扩展或替换词库时才需要调用该接口。

3.4 设置输入模式

void lv_ime_pinyin_set_mode(lv_obj_t * obj, lv_ime_pinyin_mode_t mode);

输入模式枚举:

typedef enum {
    LV_IME_PINYIN_MODE_ENGLISH,    /* 英文模式 */
    LV_IME_PINYIN_MODE_K26,        /* 26 键拼音模式 */
    LV_IME_PINYIN_MODE_K9,         /* 9 键拼音模式 */
    LV_IME_PINYIN_MODE_K9_NUMBER,  /* 9 键数字模式 */
} lv_ime_pinyin_mode_t;

常用设置:

lv_ime_pinyin_set_mode(ime, LV_IME_PINYIN_MODE_ENGLISH); /* 默认英文 */
lv_ime_pinyin_set_mode(ime, LV_IME_PINYIN_MODE_K26);     /* 默认中文 26 键 */

注意:LV_IME_PINYIN_MODE_K9LV_IME_PINYIN_MODE_K9_NUMBER 需要打开 LV_IME_PINYIN_USE_K9_MODE

3.5 获取绑定键盘

lv_obj_t * lv_ime_pinyin_get_kb(lv_obj_t * obj);

返回当前绑定的 lv_keyboard

3.6 获取候选字面板

lv_obj_t * lv_ime_pinyin_get_cand_panel(lv_obj_t * obj);

返回候选字面板对象。可用于设置候选字面板的高度、字体、背景色、文字颜色等 UI 样式。

示例:

lv_obj_t *cand_panel = lv_ime_pinyin_get_cand_panel(ime);
lv_obj_set_height(cand_panel, 36);
lv_obj_set_style_bg_color(cand_panel, lv_color_hex(0xffffff), LV_PART_MAIN);
lv_obj_set_style_bg_opa(cand_panel, LV_OPA_COVER, LV_PART_MAIN);
lv_obj_set_style_text_color(cand_panel, lv_color_hex(0x111111), LV_PART_MAIN);
lv_obj_set_style_text_color(cand_panel, lv_color_hex(0x111111), LV_PART_ITEMS);

3.7 获取词库

const lv_pinyin_dict_t * lv_ime_pinyin_get_dict(lv_obj_t * obj);

返回当前输入法使用的词库指针。

4. 最小使用流程

下面是一个最小可用示例:

#if LV_USE_IME_PINYIN
static lv_obj_t *ta;
static lv_obj_t *kb;
static lv_obj_t *ime;

void demo_create_pinyin_input(lv_obj_t *parent)
{
    /* 1. 创建文本输入框 */
    ta = lv_textarea_create(parent);
    lv_obj_set_size(ta, LV_PCT(100), 100);
    lv_obj_align(ta, LV_ALIGN_TOP_MID, 0, 0);
    lv_textarea_set_one_line(ta, false);

    /* 2. 创建键盘 */
    kb = lv_keyboard_create(parent);
    lv_obj_set_size(kb, LV_PCT(100), 160);
    lv_obj_align(kb, LV_ALIGN_BOTTOM_MID, 0, 0);
    lv_keyboard_set_textarea(kb, ta);

    /* 3. 创建拼音输入法并绑定键盘 */
    ime = lv_ime_pinyin_create(parent);
    lv_ime_pinyin_set_keyboard(ime, kb);

    /* 4. 设置初始模式:英文或中文 26 键 */
    lv_ime_pinyin_set_mode(ime, LV_IME_PINYIN_MODE_K26);

    /* 5. 设置候选字面板样式 */
    lv_obj_t *cand_panel = lv_ime_pinyin_get_cand_panel(ime);
    lv_obj_set_height(cand_panel, 36);
    lv_obj_set_style_bg_opa(cand_panel, LV_OPA_COVER, LV_PART_MAIN);
    lv_obj_set_style_bg_color(cand_panel, lv_color_hex(0xffffff), LV_PART_MAIN);
    lv_obj_set_style_text_color(cand_panel, lv_color_hex(0x111111), LV_PART_MAIN);
    lv_obj_set_style_text_color(cand_panel, lv_color_hex(0x111111), LV_PART_ITEMS);
}
#endif

5. UI 设置建议

5.1 键盘位置

建议键盘固定在页面底部:

lv_obj_set_size(kb, LV_PCT(100), keyboard_h);
lv_obj_align(kb, LV_ALIGN_BOTTOM_MID, 0, 0);

lv_ime_pinyin_set_keyboard() 会把候选面板自动对齐到键盘上方:

lv_obj_align_to(cand_panel, kb, LV_ALIGN_OUT_TOP_MID, 0, 0);

因此页面布局时,需要在键盘上方给候选面板预留一定高度。推荐候选面板高度为 32~40 像素,小屏可取 30~36 像素。

5.2 输入框高度

输入框建议不要被候选面板和键盘遮挡。可以按屏幕高度动态计算:

lv_coord_t screen_h = lv_disp_get_ver_res(NULL);
lv_coord_t header_h = 44;
lv_coord_t keyboard_h = screen_h <= 360 ? 132 : 164;
lv_coord_t cand_h = 36;
lv_coord_t textarea_h = screen_h - header_h - keyboard_h - cand_h - 10;

if (textarea_h < 62)
    textarea_h = 62;

5.3 字体设置

候选字面板需要能显示中文。若系统默认字体不包含中文,需要给输入框、键盘、候选面板设置中文字体。

本工程示例中使用 lv_ext_set_local_font()

lv_ext_set_local_font(kb, FONT_NORMAL, lv_color_hex(0x222222));
lv_ext_set_local_font(ta, FONT_SMALL, lv_color_hex(0x111111));

lv_obj_t *cand_panel = lv_ime_pinyin_get_cand_panel(ime);
lv_ext_set_local_font(cand_panel, FONT_SMALL, lv_color_hex(0x111111));

如果直接使用 LVGL 字体接口,也可以设置 LV_PART_MAINLV_PART_ITEMS

const lv_font_t *font = lv_obj_get_style_text_font(ta, LV_PART_MAIN);
lv_obj_set_style_text_font(cand_panel, font, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(cand_panel, font, LV_PART_ITEMS | LV_STATE_DEFAULT);

5.4 候选面板样式

推荐将候选面板设置为不透明背景,避免和后面的输入框或页面内容混在一起:

lv_obj_set_style_bg_color(cand_panel, lv_color_hex(0xffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(cand_panel, LV_OPA_COVER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(cand_panel, lv_color_hex(0x111111), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(cand_panel, lv_color_hex(0x111111), LV_PART_ITEMS | LV_STATE_DEFAULT);

6. 按键行为说明

拼音输入法接管键盘 LV_EVENT_VALUE_CHANGED 事件后,会处理以下按键文本:

按键

行为

英文模式下切换到中文拼音 26 键;中文模式下切回英文。

ABC

切换到英文大写,或从 9 键数字模式回到 9 键拼音。

abc

从英文大写/符号等模式切换到小写或 26 键小写布局。

1#

26 键拼音模式下切换到数字/符号布局。

9键

在 26 键拼音和 9 键拼音之间切换。

123

9 键拼音模式下切换到 9 键数字模式。

Del

删除拼音输入缓存;缓存为空时删除文本框中的字符。

Space

输入空格,并清空拼音缓存。

Enter

插入换行;若文本框是单行模式则发送 LV_EVENT_READY

OK

清空拼音缓存,隐藏候选面板,并向键盘和文本框发送 LV_EVENT_READY

< / >

普通模式下移动光标;9 键模式下翻页候选拼音。

候选字面板中:

  • 第一个按钮 <:上一页候选字。

  • 最后一个翻页按钮 >:下一页候选字。

  • 中间按钮:候选汉字,点击后写入 lv_textarea

7. 自定义词库

如果内置词库不满足客户输入需求,可以使用自定义词库。

7.1 定义词库

static lv_pinyin_dict_t custom_dict[] = {
    { "a",    "啊阿" },
    { "ai",   "爱矮挨" },
    { "an",   "安按暗" },
    { "yuan",  "元原远圆" },
    { "zhong", "中种重钟" },
    { NULL, NULL }
};

7.2 设置词库

ime = lv_ime_pinyin_create(parent);
lv_ime_pinyin_set_keyboard(ime, kb);
lv_ime_pinyin_set_dict(ime, custom_dict);
lv_ime_pinyin_set_mode(ime, LV_IME_PINYIN_MODE_K26);

注意事项:

  • 拼音字符串建议使用小写字母。

  • 词库数组必须以 { NULL, NULL } 结束,源码通过 dict[i].py == NULLdict[i].py_mb == NULL 判断结束。

  • 词库需要按拼音首字母分组排列,例如 a...b...c...,不要把 yuan 放在 zhong 后面再接其它 y 开头词条,否则按首字母索引查找时可能漏查。

  • 候选汉字字符串需要使用 UTF-8 编码。当前实现按每个中文字符 3 字节计算候选数量,候选串中不要混入 ASCII 字符或 4 字节 Unicode 字符。

  • LV_IME_PINYIN_USE_DEFAULT_DICT 为 0,必须先设置词库,否则无法正常出候选字。

  • 词库越大,占用 Flash/RAM 越多;小资源设备建议只保留业务所需词条。

8. 工程调用示例:pcalendar 编辑页面

当前工程 pcalendar 中已经有一套完整使用方式,可作为客户集成参考:

solution/examples/_dynamic_app/c/app/pcalendar/src/perpetual_calendar_gui.c

核心代码流程如下:

#if LV_USE_IME_PINYIN
g_editor.ime_mode = LV_IME_PINYIN_MODE_ENGLISH;
#endif

/* 创建键盘 */
g_editor.keyboard = lv_keyboard_create(box);
lv_obj_set_size(g_editor.keyboard, LV_PCT(100), keyboard_h);
lv_obj_align(g_editor.keyboard, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_keyboard_set_mode(g_editor.keyboard, LV_KEYBOARD_MODE_TEXT_LOWER);
lv_ext_set_local_font(g_editor.keyboard, FONT_NORMAL, lv_color_hex(0x222222));

/* 创建输入框 */
g_editor.textarea = lv_textarea_create(box);
lv_obj_set_size(g_editor.textarea, LV_PCT(100), textarea_h);
lv_obj_align(g_editor.textarea, LV_ALIGN_TOP_MID, 0, header_h);
lv_textarea_set_one_line(g_editor.textarea, false);
lv_textarea_set_text(g_editor.textarea, text ? text : "");
lv_obj_set_style_bg_color(g_editor.textarea, lv_color_hex(0xffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(g_editor.textarea, lv_color_hex(0x111111), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_ext_set_local_font(g_editor.textarea, FONT_SMALL, lv_color_hex(0x111111));
lv_obj_add_state(g_editor.textarea, LV_STATE_FOCUSED);
lv_keyboard_set_textarea(g_editor.keyboard, g_editor.textarea);

#if LV_USE_IME_PINYIN
/* 创建并绑定拼音输入法 */
g_editor.ime = lv_ime_pinyin_create(box);
lv_ime_pinyin_set_keyboard(g_editor.ime, g_editor.keyboard);
lv_obj_set_style_text_font(g_editor.ime, lv_obj_get_style_text_font(g_editor.textarea, LV_PART_MAIN), LV_PART_MAIN);

/* 候选面板 UI */
{
    const lv_font_t *editor_font = lv_obj_get_style_text_font(g_editor.textarea, LV_PART_MAIN);
    lv_obj_t *cand_panel = lv_ime_pinyin_get_cand_panel(g_editor.ime);
    lv_obj_set_height(cand_panel, 36);
    lv_ext_set_local_font(cand_panel, FONT_SMALL, lv_color_hex(0x111111));
    lv_obj_set_style_text_font(cand_panel, editor_font, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_font(cand_panel, editor_font, LV_PART_ITEMS | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(cand_panel, lv_color_hex(0xffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(cand_panel, LV_OPA_COVER, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(cand_panel, lv_color_hex(0x111111), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(cand_panel, lv_color_hex(0x111111), LV_PART_ITEMS | LV_STATE_DEFAULT);
}

/* 应用当前输入模式,pcalendar 中初始为 LV_IME_PINYIN_MODE_ENGLISH */
pcalendar_editor_apply_ime_mode();
#endif

上面的顺序与 pcalendar_open_editor() 当前实现保持一致:

  1. 创建编辑页父容器 box

  2. 创建底部键盘 g_editor.keyboard,设置大小、位置、键盘模式和字体。

  3. 创建输入框 g_editor.textarea,设置大小、位置、初始文本、背景色、文字颜色和字体。

  4. 调用 lv_keyboard_set_textarea(g_editor.keyboard, g_editor.textarea) 将键盘输入目标绑定到输入框。

  5. #if LV_USE_IME_PINYIN 下创建 g_editor.ime,调用 lv_ime_pinyin_set_keyboard() 接管键盘事件。

  6. 通过 lv_ime_pinyin_get_cand_panel() 获取候选字面板,并设置 36 px 高度、中文字体、白色不透明背景和深色文字。

  7. 调用 pcalendar_editor_apply_ime_mode(),内部实际执行 lv_ime_pinyin_set_mode(g_editor.ime, (lv_ime_pinyin_mode_t)g_editor.ime_mode)

9. 生命周期和资源释放

通常只需要删除父容器,LVGL 会递归删除输入框、键盘、输入法对象和候选面板。

如果需要单独关闭编辑页面,可以参考:

static void editor_close(void)
{
    if (editor_box)
        lv_obj_del(editor_box);
    editor_box = NULL;
    ime = NULL;
    kb = NULL;
    ta = NULL;
}

lv_ime_pinyin 析构时会尝试删除绑定的键盘和候选面板,因此建议把输入框、键盘、输入法放在同一个编辑页面容器下,由页面统一删除,避免悬空指针。

10. 常见问题

10.1 没有候选字

检查:

  1. LV_USE_IME_PINYIN 是否为 1。

  2. 是否调用了 lv_ime_pinyin_set_keyboard(ime, kb)

  3. 是否调用了 lv_keyboard_set_textarea(kb, ta)

  4. 是否有词库:

    • LV_IME_PINYIN_USE_DEFAULT_DICT = 1,或

    • 已调用 lv_ime_pinyin_set_dict() 设置自定义词库。

  5. 当前是否处于中文模式:LV_IME_PINYIN_MODE_K26LV_IME_PINYIN_MODE_K9

10.2 候选字显示为方框或乱码

原因通常是字体不包含中文字形或编码不对。

处理:

  • 确认词库字符串为 UTF-8。

  • textareakeyboardcand_panel 设置包含中文的字体。

  • 尤其要设置候选面板 LV_PART_ITEMS 的字体。

10.3 候选面板位置不对

lv_ime_pinyin_set_keyboard() 会将候选面板对齐到键盘上方。如果后续移动或改变键盘大小,建议重新调整候选面板:

lv_obj_t *cand_panel = lv_ime_pinyin_get_cand_panel(ime);
lv_obj_align_to(cand_panel, kb, LV_ALIGN_OUT_TOP_MID, 0, 0);

10.4 OK/Enter 后如何保存输入内容

OK 会向键盘和文本框发送 LV_EVENT_READY。可以给 textareakeyboard 添加事件回调,在 LV_EVENT_READY 中读取文本:

static void textarea_ready_cb(lv_event_t *e)
{
    lv_obj_t *ta = lv_event_get_target(e);
    const char *txt = lv_textarea_get_text(ta);
    /* 保存 txt */
}

lv_obj_add_event_cb(ta, textarea_ready_cb, LV_EVENT_READY, NULL);

11. 推荐集成步骤

  1. menuconfig (Top) SiFli SDK configuration Third party packages LittlevGL2RTT: The LittlevGl gui lib adapter RT-Thread (PKG_USING_LITTLEVGL2RTT) LVGL configuration select LVGL Version. LVGL V8 LVGL V8 configuration Others Enable Pinyin input method (LV_USE_IME_PINYIN) 启用拼音输入法;LV_USE_IME_PINYIN 默认关闭,启用后会自动选择 LV_USE_KEYBOARD

  2. 按页面布局创建 lv_textarea

  3. 创建 lv_keyboard,并调用 lv_keyboard_set_textarea(kb, ta)

  4. 创建 lv_ime_pinyin,调用 lv_ime_pinyin_set_keyboard(ime, kb)

  5. 根据产品需求设置初始模式:英文或中文 26 键。

  6. 设置候选面板中文字体、背景色、高度。

  7. 如需业务词库,调用 lv_ime_pinyin_set_dict()

  8. LV_EVENT_READY 或保存按钮事件中读取 lv_textarea_get_text(ta)