LVGL自定义滑动

news2025/1/12 1:05:41

请添加图片描述

触摸和编码器都可以操作


typedef struct
{
    lv_obj_t* obj;
    int16_t x;
    int16_t y;
    int16_t width;
    int16_t height;
}pos_and_size_t;

typedef struct
{
    lv_obj_t* obj;
    lv_coord_t height;
    lv_coord_t width;
    lv_coord_t width_pad;
    lv_coord_t height_pad;
    lv_coord_t child_widget;
    lv_coord_t child_height;
}widget_attr_t;

#define NUMBER_OF_MENUS    10

static pos_and_size_t ps[NUMBER_OF_MENUS+4];
static widget_attr_t widget =
{
    .height = 260,
    .height_pad = 10,
    .width = 360,
    .width_pad = 10,
};

void widget_refresh(void)
{
    for (int i = 0; i < sizeof(ps) / sizeof(ps[0]); i++)
    {
        lv_obj_set_size(ps[i].obj, ps[i].width, ps[i].height);
        lv_obj_set_pos(ps[i].obj, ps[i].x, ps[i].y);
    }
}

/**
 * @brief 根据x坐标,计算y坐标和宽度
*/
void widget_get_y_w(int x, int* y, int* w)
{
    float k1 = (2 * widget.height_pad + 3 * widget.child_height) * 1.0f / (2 * widget.width_pad + 3 * widget.child_widget);
    float b1 = widget.height_pad - k1 * widget.width_pad;
    float k2 = (3*widget.child_widget) * 1.0f / (2 * widget.width_pad + 3 * widget.child_widget);
    float b2 = widget.child_widget - k2 * widget.width_pad;

    float k3 = (2 * widget.height_pad + 3*widget.child_height) * -1.0f / (2 * widget.width_pad + 6 * widget.child_widget);
    float b3 = widget.height_pad - k3 * (5*widget.width_pad+9*widget.child_widget);
    float k4 = (3 * widget.child_widget) * -1.0f / (2 * widget.width_pad + 6 * widget.child_widget);
    float b4 = widget.child_widget - k4 * (5*widget.width_pad + 9*widget.child_widget);
    if (x < widget.width_pad)
    {
        *y = widget.height_pad;
        *w = widget.child_widget;
    }
    else if (x < 3 * widget.width_pad + 3 * widget.child_widget)
    {
        *y = k1 * x + b1;
        *w = k2 * x + b2;
    }
    else if (x < 5 * widget.width_pad + 9 * widget.child_widget)
    {
        *y = k3 * x + b3;
        *w = k4 * x + b4;
    }
    else
    {
        *y = widget.height_pad;
        *w = widget.child_widget;
    }
}


void widget_update(widget_attr_t* widget)
{
    int start_x = lv_obj_get_scroll_x(widget->obj);

    for (int i = 1; i < sizeof(ps) / sizeof(ps[0]); i++)
    {
        int x = ps[i - 1].x + ps[i - 1].width + widget->width_pad;
        int diff = (x - start_x);
        ps[i].x = x ;
        
        widget_get_y_w(diff, &ps[i].y, &ps[i].width);
        ps[i].height = ps[i].width;
    }

    int index = 1;
    for (int i = 1; i < sizeof(ps) / sizeof(ps[0]); i++)
    {
        if (ps[i].width > ps[index].width)
        {
            index = i;
        }
        lv_obj_clear_state(ps[i].obj, LV_STATE_FOCUS_KEY);
    }
    lv_obj_add_state(ps[index].obj, LV_STATE_FOCUS_KEY);

    widget_refresh();
}

/**
 * @brief 
*/
void widget_end(widget_attr_t* widget)
{
    static int start_x_old = 0;
    int start_x = lv_obj_get_scroll_x(widget->obj);

    if (abs(start_x_old - start_x) < 5)
    {
        return;
    }
    start_x_old = start_x;
    int index = 1;
    for (int i = 1; i < sizeof(ps) / sizeof(ps[0]); i++)
    {
        if (ps[i].width > ps[index].width)
        {
            index = i;
        }
        lv_obj_clear_state(ps[i].obj, LV_STATE_FOCUS_KEY);
    }

    lv_obj_scroll_to_x(widget->obj, (index-2)*(widget->width_pad + widget->child_widget), LV_ANIM_OFF);
    lv_group_focus_obj(ps[index].obj);
    lv_obj_add_state(ps[index].obj, LV_STATE_FOCUS_KEY);
}

lv_timer_t* s_timer = NULL;
static void timer_cb(lv_timer_t* t)
{
    lv_timer_pause(s_timer);
    widget_end(&widget);
}


static widget_cb(lv_event_t* e)
{
    lv_event_code_t code = lv_event_get_code(e);
    if (LV_EVENT_SCROLL == code)
    {
        lv_timer_pause(s_timer);
        widget_update(&widget);
    }
    else if(code == LV_EVENT_SCROLL_END)
    {
        //结束滑动时,如果没有控件在最中间位置,将最近的控件滑动到最中间
        lv_timer_reset(s_timer);
        lv_timer_resume(s_timer);
    }
    
}


static btn_cb(lv_event_t* e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t* obj = lv_event_get_target(e);
    if (LV_EVENT_FOCUSED == code)
    {
        //焦点移动时,滑动控件,始终保持最中间控件聚焦
        int index = lv_event_get_user_data(e);
        lv_obj_scroll_to_x(lv_obj_get_parent(obj), (index - 2) * (widget.width_pad + widget.child_widget), LV_ANIM_OFF);
    }
}
void widget_init(void)
{
    widget.child_widget = (widget.width - 6 * widget.width_pad) / 10;
    widget.child_height = (widget.height - 2 * widget.height_pad) / 8;

    widget.obj = lv_obj_create(lv_scr_act());
    lv_obj_set_size(widget.obj, widget.width, widget.height);
    //lv_obj_set_scrollbar_mode(widget.obj, LV_SCROLLBAR_MODE_OFF);
    lv_obj_set_style_bg_opa(widget.obj, LV_OPA_0, LV_STATE_DEFAULT);
    lv_obj_set_style_pad_all(widget.obj, 0, LV_STATE_DEFAULT);
    //lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_CENTER);
    lv_obj_clear_flag(widget.obj, LV_OBJ_FLAG_SCROLL_ELASTIC);

    s_timer = lv_timer_create(timer_cb, 100, 0);
    lv_timer_pause(s_timer);

    //创建初始屏幕,显示5个控件,宽度 1, 2, 4, 2, 1,
    for (int i = 0; i < sizeof(ps) / sizeof(ps[0]); i++)
    {
        ps[i].obj = lv_btn_create(widget.obj);
        lv_obj_t* lab = lv_label_create(ps[i].obj);
        lv_label_set_text_fmt(lab, "%d", i);
        lv_obj_align(lab, LV_ALIGN_CENTER, 0, 0);
        lv_obj_set_scrollbar_mode(ps[i].obj, LV_SCROLLBAR_MODE_OFF);
        lv_obj_add_event_cb(ps[i].obj, btn_cb, LV_EVENT_ALL, i);
        ps[i].width = widget.child_widget;
        ps[i].height = widget.child_height;
    }

    ps[1].width = widget.child_widget*2;
    ps[1].height = widget.child_height*2;
    
    ps[2].width = widget.child_widget*4;
    ps[2].height = widget.child_height*4;
    
    ps[3].width = widget.child_widget*2;
    ps[3].height = widget.child_height*2;
    

    ps[0].x = widget.width_pad;
    ps[0].y = widget.height_pad;
    for (int i = 1; i < sizeof(ps) / sizeof(ps[0]); i++)
    {
        ps[i].y = widget.height_pad;
        ps[i].x = widget.width_pad + ps[i - 1].x + ps[i - 1].width;
    }
    ps[1].y = widget.height_pad*2 + widget.child_height;
    ps[2].y = widget.height_pad*3 + widget.child_height*3;
    ps[3].y = widget.height_pad*2 + widget.child_height;

    //隐藏开头两个
    lv_obj_add_flag(ps[0].obj, LV_OBJ_FLAG_HIDDEN);
    lv_obj_add_flag(ps[1].obj, LV_OBJ_FLAG_HIDDEN);

    //隐藏最后两个
    lv_obj_add_flag(lv_obj_get_child(ps[NUMBER_OF_MENUS + 2].obj, -1), LV_OBJ_FLAG_HIDDEN);
    lv_obj_add_flag(lv_obj_get_child(ps[NUMBER_OF_MENUS + 3].obj, -1), LV_OBJ_FLAG_HIDDEN);

    lv_obj_remove_style_all(ps[NUMBER_OF_MENUS + 2].obj);
    lv_obj_remove_style_all(ps[NUMBER_OF_MENUS + 3].obj);
    lv_obj_set_style_border_width(ps[NUMBER_OF_MENUS + 2].obj, 0, LV_STATE_DEFAULT);
    lv_obj_set_style_border_width(ps[NUMBER_OF_MENUS + 3].obj, 0, LV_STATE_DEFAULT);

    lv_obj_set_style_bg_opa(ps[NUMBER_OF_MENUS + 2].obj, LV_OPA_0, LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ps[NUMBER_OF_MENUS + 3].obj, LV_OPA_0, LV_STATE_DEFAULT);


    lv_obj_add_event_cb(widget.obj, widget_cb, LV_EVENT_ALL, NULL);
    widget_refresh();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1635776.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

监控操作台为生活提供安全保障

在科技日新月异的现代社会&#xff0c;监控操作台已成为我们生活中不能缺少的一部分。它犹如一座城市的守护神&#xff0c;默默无闻地守护着我们的安全&#xff0c;确保着每一刻的平安。今天&#xff0c;和北京嘉德立一同走进这个神秘的世界&#xff0c;揭开监控操作台的神秘面…

(十四)Servlet教程——Servlet中HttpSession的使用

除了使用Cookie&#xff0c;Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制&#xff0c;相应地也增加了服务器的存储压力。 1. 什么是Session Session是另外一种记录客户端状态的机制&#xff0c;不同的是Cookie保存在客户…

线程池嵌套导致的死锁问题

1、背景 有一个报告功能&#xff0c;报告需要生成1个word&#xff0c;6个excel附件&#xff0c;总共7个文件&#xff0c;需要记录报告生成进度&#xff0c;进度字段jd初始化是0&#xff0c;每个文件生成成功进度加1&#xff0c;生成失败就把生成状态置为失败。 更新进度语句&…

Vue入门到关门之Vue项目工程化

一、创建Vue项目 1、安装node环境 官网下载&#xff0c;无脑下一步&#xff0c;注意别放c盘就行 Node.js — Run JavaScript Everywhere (nodejs.org) 需要两个命令 npm---->pipnode—>python 装完检查一下&#xff0c;hello world检测&#xff0c;退出crtlc 2、搭建vu…

Linux:浏览器访问网站的基本流程(优先级从先到后)

浏览器访问网站的基本流程&#xff08;优先级从先到后&#xff09; 首先查找浏览器是否存在该网站的访问缓存 其次查找本机的域名解析服务器 windows&#xff1a;C:\Windows\System32\drivers\etc\hostsLinux&#xff1a;/etc/hosts 使用外部的域名解析服务器解析&#xff…

逆向第一步 去掉debugger(无任何门槛小白可学习)

准备工具 1.ReRes 地址&#xff1a;ReRes 用法&#xff1a; 用法 2.nodepad 地址&#xff1a;nodepad 注意下载后缀为.x64.exe版本的 我这里下的npp.8.6.5.Installer.x64.exe 3给nodepad装上JSTool插件 下载 可省略下叙详细步骤点此链接直接下载 JSToolNpp 然后到导…

Go语言基本语法(三)指针

什么是指针 在Go语言中&#xff0c;"指针是一种存储变量内存地址的数据类型"&#xff0c;意味着指针本身是一个特殊的变量&#xff0c;它的值不是数据本身&#xff0c;而是另一个变量在计算机内存中的位置&#xff08;地址&#xff09;。形象地说&#xff0c;就像存…

Avalonia .NET构建Linux桌面应用

目录 &#x1f47b;前言 &#x1f4bb;安装Avalonia &#x1f4e6;创建项目 &#x1f4da;在win下运行 ​&#x1f511;打包发布​编辑 &#x1f4fb;在linux下运行 环境WIN10 VS2022 debian &#x1f47b;前言 Avalonia 是一个用于创建跨平台用户界面 (UI) 的开源框架…

C++——STL容器——vector

vector是STL容器的一种&#xff0c;和我们在数据结构中所学的顺序表结构相似&#xff0c;其使用和属性可以仿照顺序表的形式。vector的本质是封装了一个动态大小的数组&#xff0c;支持动态管理容量、数据的顺序存储以及随机访问。 1.前言说明 vector作为容器&#xff0c;应该…

对6个默认成员函数的总结

前言&#xff1a;本篇文章是对六大默认成员函数的自我总结&#xff0c;不适合刚入门的新人学习。适合想进一步深入了解六大默认成员函数的人学习。 1.构造函数&#xff1a;给对象初始化的函数&#xff0c;相当于之前写的Init函数。 构造函数的特性&#xff1a; 对内置类型不…

深度解析:人工智能作画算法的原理与技术

引言 在数字艺术的探索中&#xff0c;人工智能&#xff08;AI&#xff09;作画算法以其独特的创造性和艺术性引起了广泛的兴趣。这些算法不仅仅是简单的图像处理工具&#xff0c;它们背后蕴藏着复杂的神经网络和深度学习模型。本文将深入探讨AI作画算法的原理与技术&#xff0…

day15 学一下Tailwindcss(java转ts全栈/3r教室)

目前距离全栈差得最多的是前端&#xff0c;而对于前端主要是CSS一直不熟悉&#xff0c;觉得很复杂写起来总是不上道&#xff0c;所以特别关注下Tailwindcss吧&#xff0c;其他前端框架可以先放放&#xff0c;多说无益直接用tailwindcss做个页面试试 看下文档&#xff1a;Tailwi…

【LeetCode刷题记录】104. 二叉树的最大深度

104 二叉树的最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 示例 2&#xff1a; 输入&#xff…

HarmonyOS开发案例:【排行榜页面】

介绍 本课程使用声明式语法和组件化基础知识&#xff0c;搭建一个可刷新的排行榜页面。在排行榜页面中&#xff0c;使用循环渲染控制语法来实现列表数据渲染&#xff0c;使用Builder创建排行列表布局内容&#xff0c;使用装饰器State、Prop、Link来管理组件状态。最后我们点击…

基于python+django网易新闻+评论的舆情热点分析平台

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Php和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

回溯Backtracking Algorithm

目录 1) 入门例子 2) 全排列-Leetcode 46 3) 全排列II-Leetcode 47 4) 组合-Leetcode 77 5) 组合总和-Leetcode 39 6) 组合总和 II-Leetcode 40 7) 组合总和 III-Leetcode 216 8) N 皇后 Leetcode 51 9) 解数独-Leetcode37 10) 黄金矿工-Leetcode1219 其它题目 1) 入…

LeetCode45:跳跃游戏Ⅱ

题目描述 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n …

SAP PP学习笔记08 - 作业区(工作中心Work Center),作业区Customize

上一章讲了作业手顺&#xff08;工艺路线Routing&#xff09;。 SAP PP学习笔记07 - 作业手顺&#xff08;工艺路线Routing&#xff09;-CSDN博客 这一章来讲讲作业区&#xff08;工作中心 Work Center&#xff09;。 1&#xff0c;作业区&#xff08;工作中心&#xff09;中…

Linux挂载硬盘

1、查看硬盘数量 fdisk -l # 可以看到三个磁盘 # /dev/vda 50G # /dev/vdb 100G 新增 # /dev/vdc 100G 新增2、查看当前挂载情况 df -h # 可以看到50G的已经挂载3、格式化待挂载盘 # 对新的数据盘进行挂载前要进行格式化&#xff0c;只有格式化后才可以挂载 mkfs.ext4 /dev/…

2024年这样做抖音小店,操作简单,起店稳定!

大家好&#xff0c;我是电商糖果 不少朋友说跟糖果抱怨过&#xff0c;说抖音小店越来越难做了。 平台的规则越来越多&#xff0c;商家运营店铺的时候&#xff0c;很容易出现违规预警。 糖果是2020年开始做的抖音小店&#xff0c;现在已经经营了多家小店。 实话实说确实比之…