Rust+Slint 实现圆形变色按钮源码分享

Rust+Slint 实现圆形变色按钮源码分享

  • 一、效果展示
  • 二、源码分享
  • 三、实现原理
    • 1、组件架构设计
      • [1.1 、分层结构](#1.1 、分层结构)
      • [1.2 、属性系统](#1.2 、属性系统)
    • 2、水波纹效果实现
      • [2.1 、动态尺寸计算](#2.1 、动态尺寸计算)
      • [2.2、 位置跟踪机制](#2.2、 位置跟踪机制)
      • [2.3、 渐变颜色设计](#2.3、 渐变颜色设计)
    • [3、 交互逻辑实现](#3、 交互逻辑实现)
      • [3.1 鼠标事件处理](#3.1 鼠标事件处理)
      • [3.2 、悬停状态检测](#3.2 、悬停状态检测)
    • 4、动画与过渡效果
      • [4.1 、缓动函数配置](#4.1 、缓动函数配置)
      • [4.2、 视觉细节优化](#4.2、 视觉细节优化)
    • [5、 Rust 后端集成](#5、 Rust 后端集成)
      • [5.1 、模块包含机制](#5.1 、模块包含机制)
      • [5.2、 窗口创建流程](#5.2、 窗口创建流程)
    • [6、 构建系统配置](#6、 构建系统配置)
      • [6.1、 构建脚本](#6.1、 构建脚本)
      • [6.2 、依赖管理](#6.2 、依赖管理)
    • 7、设计模式总结
      • [7.1 、响应式设计](#7.1 、响应式设计)
      • [7.2、 性能优化](#7.2、 性能优化)
      • [7.3、 可扩展性](#7.3、 可扩展性)
    • 8、技术亮点

一、效果展示

二、源码分享

1、工程结构

2、main.rs

rust 复制代码
slint::include_modules!();

fn main() -> Result<(), slint::PlatformError> {
    let main_window = MainWindow::new()?;
    main_window.run()
}

3、build.rs

rust 复制代码
fn main() {
    // 编译 Slint UI
    slint_build::compile("ui/main.slint").unwrap();
}

4、main.slint

rust 复制代码
// 高端水波纹扩散按钮组件
component WaveButton {
    in property <string> text;
    in property <color> background-color: rgb(30, 40, 80);
    in property <color> ripple-color: #ff6b35;
    in property <color> font-color: #ffffff;
    in property <length> border-radius: 15px;
    in property <length> font-size: 22px;

    // 记录鼠标离开时的位置
    in-out property <length> exit-x: 0px;
    in-out property <length> exit-y: 0px;

    width: 240px;
    height: 80px;

    // 阴影层
    Rectangle {
        width: root.width;
        height: root.height;
        border-radius: root.border-radius;
        background: #00000040;
        y: 4px;
    }

    // 主容器 - 圆角裁剪
    Rectangle {
        width: root.width;
        height: root.height;
        border-radius: root.border-radius;
        clip: true;

        // 渐变背景
        background: @linear-gradient(135deg,
            rgb(40, 50, 100) 0%,
            rgb(30, 40, 80) 50%,
            rgb(20, 30, 70) 100%);

        // 边框高光效果
        border-width: 1px;
        border-color: #ffffff1a;

        // 水波纹圆形 - 跟随鼠标位置
        ripple-circle := Rectangle {
            width: touch-area.has-hover ? parent.width * 3  : 0px;
            height: touch-area.has-hover ? parent.width * 3  : 0px;
            // 当悬停时跟随鼠标,离开时使用记录的位置
            x: touch-area.has-hover ? touch-area.mouse-x - self.width / 2 : root.exit-x - self.width / 2;
            y: touch-area.has-hover ? touch-area.mouse-y - self.height / 2 : root.exit-y - self.height / 2;
            border-radius: self.width / 2;
            background: @radial-gradient(circle, #ff6b35 0%, #ff6b35cc 40%, #ff6b3500 70%);

            // 平滑动画
            animate width, height { duration: 600ms; easing: cubic-bezier(0.4, 0, 0.2, 1); }
        }

        // 文字层
        Text {
            width: parent.width;
            height: parent.height;
            text: root.text;
            color: root.font-color;
            font-size: root.font-size;
            horizontal-alignment: center;
            vertical-alignment: center;
        }
    }

    // 鼠标交互区域
    touch-area := TouchArea {
        width: root.width;
        height: root.height;

        pointer-event(event) => {
            if(event.kind == PointerEventKind.move)
            {
                root.exit-x = self.mouse-x;
                root.exit-y = self.mouse-y;
            }
        }
    }
}

// 主窗口
export component MainWindow inherits Window {
    preferred-width: 800px;
    preferred-height: 700px;
    title: "Premium Wave Buttons";

    // 深色渐变背景
    background: @linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);

    // 垂直布局实现居中
    VerticalLayout {
        alignment: center;


        // 间距
        Rectangle {
            height: 60px;
        }

        // 水平布局放置两个按钮
        HorizontalLayout {
            alignment: center;
            spacing: 80px;

            WaveButton {
                text: "按钮一";
            }

            WaveButton {
                text: "按钮二";
            }
        }
    }
}

5、Cargo.toml

rust 复制代码
[package]
name = "sokoban"
version = "0.1.0"
edition = "2024"

[dependencies]
slint = "1.16.1"

[build-dependencies]
slint-build = "1.16.1"

三、实现原理

本文实现的圆形变色按钮基于 Rust + Slint 框架,通过声明式 UI 语法和响应式属性系统,实现了具有水波纹扩散效果的高交互性按钮组件。以下是详细的技术实现原理:

1、组件架构设计

1.1 、分层结构

按钮采用三层视觉结构:

  1. 阴影层:最底层的半透明黑色矩形,提供立体感和深度
  2. 主容器层:带有圆角裁剪和渐变背景的矩形,承载水波纹效果
  3. 文字层:显示按钮文本,始终位于最上层

1.2 、属性系统

组件通过 Slint 的属性系统实现数据绑定和响应式更新:

  • in property:输入属性,外部可配置(如文本、颜色、尺寸)
  • in-out property:双向属性,内部状态管理(如鼠标离开位置)

2、水波纹效果实现

2.1 、动态尺寸计算

rust 复制代码
ripple-circle := Rectangle {
    width: touch-area.has-hover ? parent.width * 3 : 0px;
    height: touch-area.has-hover ? parent.width * 3 : 0px;
}
  • 悬停时:水波纹圆形直径扩大到父容器宽度的3倍
  • 非悬停时:尺寸为0,实现平滑消失效果

2.2、 位置跟踪机制

rust 复制代码
x: touch-area.has-hover ? touch-area.mouse-x - self.width / 2 : root.exit-x - self.width / 2;
y: touch-area.has-hover ? touch-area.mouse-y - self.height / 2 : root.exit-y - self.height / 2;
  • 悬停状态 :实时跟随鼠标位置,mouse-x/mouse-y 提供精确坐标
  • 离开状态 :使用记录的 exit-x/exit-y 位置,避免突然跳回原点

2.3、 渐变颜色设计

rust 复制代码
background: @radial-gradient(circle, #ff6b35 0%, #ff6b35cc 40%, #ff6b3500 70%);
  • 中心点:纯色 #ff6b35(橙色)
  • 40%位置:带透明度 cc(80%不透明度)
  • 70%位置:完全透明 00,实现自然淡出效果

3、 交互逻辑实现

3.1 鼠标事件处理

rust 复制代码
touch-area := TouchArea {
    pointer-event(event) => {
        if(event.kind == PointerEventKind.move) {
            root.exit-x = self.mouse-x;
            root.exit-y = self.mouse-y;
        }
    }
}
  • 实时记录:鼠标移动时持续更新离开位置
  • 平滑过渡:确保鼠标离开时水波纹从最后位置开始消失,而非瞬间重置

3.2 、悬停状态检测

  • touch-area.has-hover:内置悬停状态属性
  • 自动管理状态切换,无需手动跟踪鼠标进入/离开事件

4、动画与过渡效果

4.1 、缓动函数配置

rust 复制代码
animate width, height { duration: 600ms; easing: cubic-bezier(0.4, 0, 0.2, 1); }
  • 持续时间:600毫秒,提供足够明显的动画效果
  • 缓动曲线cubic-bezier(0.4, 0, 0.2, 1) 实现先加速后减速的自然运动
  • 同步动画:宽度和高度同时变化,保持圆形比例

4.2、 视觉细节优化

  1. 边框高光border-color: #ffffff1a 添加轻微白色边框增强质感
  2. 渐变背景:135度线性渐变创建深度感
  3. 圆角统一 :所有层使用相同的 border-radius 确保视觉一致性

5、 Rust 后端集成

5.1 、模块包含机制

rust 复制代码
slint::include_modules!();
  • 编译时:build.rs.slint 文件编译为 Rust 代码
  • 运行时:include_modules! 宏引入生成的 UI 模块

5.2、 窗口创建流程

rust 复制代码
fn main() -> Result<(), slint::PlatformError> {
    let main_window = MainWindow::new()?;
    main_window.run()
}
  1. 创建主窗口实例
  2. 运行事件循环
  3. 错误处理:返回 PlatformError 类型结果

6、 构建系统配置

6.1、 构建脚本

rust 复制代码
// build.rs
slint_build::compile("ui/main.slint").unwrap();
  • 预处理:将声明式 UI 编译为 Rust 结构体
  • 错误处理:使用 unwrap 简化示例,生产环境应处理错误

6.2 、依赖管理

toml 复制代码
[dependencies]
slint = "1.16.1"

[build-dependencies]
slint-build = "1.16.1"
  • 运行时依赖:slint 提供 UI 框架
  • 构建时依赖:slint-build 处理 UI 编译

7、设计模式总结

7.1 、响应式设计

  • 属性绑定:UI 自动响应属性变化
  • 状态驱动:悬停状态触发视觉反馈
  • 声明式语法:描述"是什么"而非"如何做"

7.2、 性能优化

  1. 裁剪优化clip: true 限制渲染区域
  2. 动画优化:硬件加速的 CSS 样式动画
  3. 事件优化:最小化事件处理逻辑

7.3、 可扩展性

  1. 参数化设计:所有视觉属性均可外部配置
  2. 组件化WaveButton 可作为独立组件复用
  3. 布局灵活:支持嵌套在任意布局容器中

8、技术亮点

  1. 零运行时成本:Slint 编译时生成高效 Rust 代码
  2. 类型安全:Rust 编译器保证 UI 逻辑的正确性
  3. 跨平台:同一代码库支持 Windows、macOS、Linux
  4. 内存安全:Rust 所有权系统避免内存错误

图:实现原理架构图 - 展示了组件分层、事件流和数据绑定关系

相关推荐
flyxl36 分钟前
DataZen 架构设计(一):一个现代桌面数据库工具是如何构建的
rust
k4m7v2pz41 分钟前
用 rust-verb-shell 重写进程管理:从 game.sh 到 .rvs 的迁移实录
开发语言·后端·rust
mldong12 小时前
同一份 15 个流程 JSON,第六种语言也跑通了:工作流引擎 Rust 移植实录
架构·rust
Naylor2 天前
只借不占:Rust 的引用与借用
后端·rust
对象存储与RustFS2 天前
RustFS 后台扫描器与自愈调参:五档速度、位腐检测周期与并发上限
后端·rust·开源
q平面人3 天前
【总工笔记】mindoc平板、桌面端笔记软件,发布到mindoc服务端
rust·tauri·华为平板·mindoc·总工笔记
MC皮蛋侠客3 天前
Tauri 2.x 系列(九):安全模型——Capabilities、Permissions、Scope 与 CSP
rust·tauri
Source.Liu3 天前
【Dioxus】Windows 环境下 Rust + Dioxus 安装配置笔记
windows·rust·dioxus
zLLM_Lab3 天前
不装 Python/PyTorch:8.1 MB Rust 程序在 MacBook Air M5 跑多模态大模型
rust