[Arduino资料] 零知开源——STM32F4实现ILI9486显示屏UI界面系列教程(二):日历功能实现

[复制链接]
 楼主| lingzhiLab 发表于 2025-6-25 17:28 | 显示全部楼层 |阅读模式
本教程将指导您在STM32F4平台上实现一个功能完善的日历应用,通过ILI9486电阻触摸屏提供直观的日期查看和交互体验。该日历应用是智能设备UI系统中的核心组件,具有以下核心功能:月份视图展示、流畅的交互体验、日期标记系统

一、硬件连接(同电子书教程)硬件连接方式与电子书阅读器完全一致,请参考系列教程(一)的硬件连接部分。显示屏直接插入零知增强板专用接口,无需额外连线。
直达链接:零知开源——STM32F4实现ILI9486显示屏UI界面系列教程(一):电子书阅读器功能
ILI9486扩展板显示屏及日历UI页面图:
d2a5f0f6-ec8c-492a-ac4a-8166f292bdb8(1).jpg



二、软件UI组件实现2.1 核心数据结构
  1. // 静态变量用于存储触摸状态
  2. static lv_point_t calendar_touch_start;
  3. static lv_calendar_ext_t * calendar_cal_ext;


2.2 触摸事件处理
  1. // 日历事件处理函数
  2. static void calendar_event_cb(lv_obj_t * obj, lv_event_t event)
  3. {
  4.     if (event == LV_EVENT_PRESSED) {
  5.         lv_indev_t * indev = lv_indev_get_act();
  6.         if (indev) {
  7.             lv_indev_get_point(indev, &calendar_touch_start);
  8.         }
  9.     }
  10.     else if (event == LV_EVENT_RELEASED) {
  11.         lv_indev_t * indev = lv_indev_get_act();
  12.         lv_point_t touch_end;
  13.         if (indev) {
  14.             lv_indev_get_point(indev, &touch_end);
  15.             lv_coord_t dx = touch_end.x - calendar_touch_start.x;
  16.             
  17.             // 滑动阈值判断
  18.             if (abs(dx) > 30) {
  19.                 if (dx > 0) {
  20.                     // 向右滑动:上个月
  21.                     if (calendar_cal_ext->showed_date.month <= 1) {
  22.                         calendar_cal_ext->showed_date.month = 12;
  23.                         calendar_cal_ext->showed_date.year--;
  24.                     } else {
  25.                         calendar_cal_ext->showed_date.month--;
  26.                     }
  27.                 } else {
  28.                     // 向左滑动:下个月
  29.                     if (calendar_cal_ext->showed_date.month >= 12) {
  30.                         calendar_cal_ext->showed_date.month = 1;
  31.                         calendar_cal_ext->showed_date.year++;
  32.                     } else {
  33.                         calendar_cal_ext->showed_date.month++;
  34.                     }
  35.                 }
  36.                 lv_obj_invalidate(obj);
  37.             }
  38.         }
  39.     }
  40. }


2.3 初始化界面
  1. void show_app_calendar()
  2. {
  3.     lv_obj_t *win = create_app_win("Calendar");
  4.     lv_coord_t hres = lv_disp_get_hor_res(NULL);
  5.     lv_coord_t vres = lv_disp_get_ver_res(NULL);
  6.    
  7.     // 创建日历对象
  8.     lv_obj_t * calendar = lv_calendar_create(win, NULL);
  9.     lv_obj_set_size(calendar, hres - 40, vres - 100);
  10.     lv_obj_align(calendar, NULL, LV_ALIGN_CENTER, 0, 10);
  11.    
  12.     // 设置当前日期
  13.     lv_calendar_date_t today;
  14.     today.year = 2025;
  15.     today.month = 6;
  16.     today.day = 18;
  17.     lv_calendar_set_today_date(calendar, &today);
  18.     lv_calendar_set_showed_date(calendar, &today);
  19.    
  20.     // 设置高亮日期(示例)
  21.     static lv_calendar_date_t highlighted_dates[2];
  22.     highlighted_dates[0].year = 2025;
  23.     highlighted_dates[0].month = 6;
  24.     highlighted_dates[0].day = 20;
  25.    
  26.     highlighted_dates[1].year = 2025;
  27.     highlighted_dates[1].month = 6;
  28.     highlighted_dates[1].day = 25;
  29.    
  30.     lv_calendar_set_highlighted_dates(calendar, highlighted_dates, 2);
  31.    
  32.     // 设置样式(可选)
  33.     static lv_style_t style_today_box;
  34.     lv_style_copy(&style_today_box, lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_TODAY_BOX));
  35.     style_today_box.body.border.color = LV_COLOR_RED;
  36.     style_today_box.body.border.width = 2;
  37.     lv_calendar_set_style(calendar, LV_CALENDAR_STYLE_TODAY_BOX, &style_today_box);
  38.    
  39.     static lv_style_t style_highlighted_days;
  40.     lv_style_copy(&style_highlighted_days, lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS));
  41.     style_highlighted_days.text.color = LV_COLOR_BLUE;
  42.     lv_calendar_set_style(calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, &style_highlighted_days);
  43.    
  44.     // 保存日历扩展数据用于事件处理
  45.     calendar_cal_ext = lv_obj_get_ext_attr(calendar);
  46.    
  47.     // 设置事件回调
  48.     lv_obj_set_event_cb(calendar, calendar_event_cb);
  49.    
  50.     // 添加滑动提示文本
  51.     lv_obj_t * hint_label = lv_label_create(win, NULL);
  52.     lv_label_set_text(hint_label, "Swipe left/right to change month");
  53.     lv_obj_align(hint_label, calendar, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
  54.     lv_obj_set_style(hint_label, &lv_style_plain_color);
  55. }


2.4 功能说明
通过左右滑动实现自然流畅的月份切换
可标记重要日期(如会议、生日)
当前日期有特殊红色边框标识
触摸日期时有视觉反馈效果


三、零知IDE配置(同电子书教程)请参考系列教程(一)的零知IDE配置部分,确保:
正确配置LCD屏幕驱动
启用触摸屏支持
添加LVGL库依赖

四、演示效果4.1 功能演示
主界面点击日历图标进入应用
查看当前月份日期布局
左右滑动切换不同月份
点击查看高亮日期的详细信息

4.2 视频效果

日历界面显示当前月份,高亮日期为蓝色,今日有红色边框


4.3 性能指标
项目 数值 说明
月份切换响应 < 80ms 从滑动到页面刷新的时间
内存占用 38KB 包括LVGL和日历数据
刷新率40Hz 日历界面刷新频率
触摸精度 ±2像素 日期选择精度


五、常见问题解决5.1 日期显示错位解决方案
  1. // 在日历创建后添加布局刷新
  2. lv_obj_refresh_ext_draw_pad(calendar);

5.2 滑动不灵敏优化方案
  1. // 降低滑动检测阈值(原30像素改为20像素)
  2. if (abs(dx) > 20) {
  3.     // 月份切换逻辑
  4. }

5.3 高亮日期不显示检查步骤
确认日期格式正确:{年, 月, 日}
检查高亮日期数组大小匹配
验证样式是否正确应用:
  1. // 调试打印当前样式
  2. lv_style_t *style = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS);
  3. Serial.printf("Text color: %d\n", style->text.color.full);

六、总结与扩展6.1 实现总结本教程实现了日历的核心功能:
直观的月份/日期展示
流畅的滑动切换体验
重要日期标记功能
实时日期显示集成

6.2 扩展建议
  1. //1.添加事件提醒
  2. typedef struct {
  3.     lv_calendar_date_t date;
  4.     char event[32]; // 事件描述
  5. } CalendarEvent;

  6. //2.周视图切换
  7. lv_obj_t *btn_switch = lv_btn_create(win, NULL);
  8. lv_obj_set_event_cb(btn_switch, switch_view_cb);

  9. //农历支持
  10. const char* get_lunar_date(uint8_t month, uint8_t day);

6.3 下一步在下一个系列教程中,我们将实现记事本键盘和显示功能。
​ ▶零知实验室 - 让嵌入式开发更简单:
www.lingzhilab.comhttp://www.lingzhilab.com/

✔零知开源是一个真正属于国人自己的开源软硬件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。
✔零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!
✔访问零知开源平台,获取更多实战项目和教程资源吧!​


您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

33

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部